From ac4c8b3ca798c486a3c86ad71eb4d16352a486be Mon Sep 17 00:00:00 2001 From: David Luzar Date: Tue, 21 Mar 2023 18:48:49 +0100 Subject: [PATCH 001/451] fix: chrome crashing when embedding scene on chrome arm (#6383) --- src/data/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/data/index.ts b/src/data/index.ts index 89877aab9..20ba75ebe 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -89,7 +89,9 @@ export const exportCanvas = async ( return await fileSave(blob, { description: "Export to PNG", name, - extension: appState.exportEmbedScene ? "excalidraw.png" : "png", + // FIXME reintroduce `excalidraw.png` when most people upgrade away + // from 111.0.5563.64 (arm64), see #6349 + extension: /* appState.exportEmbedScene ? "excalidraw.png" : */ "png", fileHandle, }); } else if (type === "clipboard") { From 83383977f58182e3dd80dc2ade2b9b51434455fe Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Wed, 22 Mar 2023 11:32:38 +0530 Subject: [PATCH 002/451] feat: add line height attribute to text element (#6360) * feat: add line height attribute to text element * lint * update line height when redrawing text bounding box * fix tests * retain line height when pasting styles * fix test * create a util for calculating ling height using old algo * update line height when resizing multiple text elements * make line height backward compatible * udpate line height for older element when font size updated * remove logs * Add specs * lint * review fixes * simplify by changing `lineHeight` from px to unitless * make param non-optional * update comment * fix: jumping text due to font size being calculated incorrectly * update line height when font family is updated * lint * Add spec * more specs * rename to getDefaultLineHeight * fix getting lineHeight for potentially undefined fontFamily * reduce duplication * fix fallback * refactor and comment tweaks * fix --------- Co-authored-by: dwelle --- src/actions/actionBoundText.tsx | 1 + src/actions/actionProperties.tsx | 2 + src/actions/actionStyles.ts | 17 ++- src/components/App.tsx | 39 +++--- src/data/restore.ts | 22 +++- src/element/newElement.ts | 13 +- src/element/resizeElements.ts | 28 +++-- src/element/textElement.test.ts | 60 ++++++--- src/element/textElement.ts | 116 ++++++++++++++---- src/element/textWysiwyg.test.tsx | 65 +++++++--- src/element/textWysiwyg.tsx | 21 ++-- src/element/types.ts | 5 + src/renderer/renderElement.ts | 20 +-- .../linearElementEditor.test.tsx.snap | 2 +- src/tests/clipboard.test.tsx | 34 +++-- .../data/__snapshots__/restore.test.ts.snap | 4 +- src/tests/helpers/api.ts | 6 +- src/tests/linearElementEditor.test.tsx | 14 +-- 18 files changed, 326 insertions(+), 143 deletions(-) diff --git a/src/actions/actionBoundText.tsx b/src/actions/actionBoundText.tsx index bdf1df60c..639a003fc 100644 --- a/src/actions/actionBoundText.tsx +++ b/src/actions/actionBoundText.tsx @@ -45,6 +45,7 @@ export const actionUnbindText = register({ const { width, height } = measureText( boundTextElement.originalText, getFontString(boundTextElement), + boundTextElement.lineHeight, ); const originalContainerHeight = getOriginalContainerHeightFromCache( element.id, diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index 309e46bdc..08420d9ef 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -54,6 +54,7 @@ import { mutateElement, newElementWith } from "../element/mutateElement"; import { getBoundTextElement, getContainerElement, + getDefaultLineHeight, } from "../element/textElement"; import { isBoundToContainer, @@ -637,6 +638,7 @@ export const actionChangeFontFamily = register({ oldElement, { fontFamily: value, + lineHeight: getDefaultLineHeight(value), }, ); redrawTextBoundingBox(newElement, getContainerElement(oldElement)); diff --git a/src/actions/actionStyles.ts b/src/actions/actionStyles.ts index b2be3853d..aaa59d324 100644 --- a/src/actions/actionStyles.ts +++ b/src/actions/actionStyles.ts @@ -12,7 +12,10 @@ import { DEFAULT_FONT_FAMILY, DEFAULT_TEXT_ALIGN, } from "../constants"; -import { getBoundTextElement } from "../element/textElement"; +import { + getBoundTextElement, + getDefaultLineHeight, +} from "../element/textElement"; import { hasBoundTextElement, canApplyRoundnessTypeToElement, @@ -92,12 +95,18 @@ export const actionPasteStyles = register({ }); if (isTextElement(newElement)) { + const fontSize = + elementStylesToCopyFrom?.fontSize || DEFAULT_FONT_SIZE; + const fontFamily = + elementStylesToCopyFrom?.fontFamily || DEFAULT_FONT_FAMILY; newElement = newElementWith(newElement, { - fontSize: elementStylesToCopyFrom?.fontSize || DEFAULT_FONT_SIZE, - fontFamily: - elementStylesToCopyFrom?.fontFamily || DEFAULT_FONT_FAMILY, + fontSize, + fontFamily, textAlign: elementStylesToCopyFrom?.textAlign || DEFAULT_TEXT_ALIGN, + lineHeight: + elementStylesToCopyFrom.lineHeight || + getDefaultLineHeight(fontFamily), }); let container = null; if (newElement.containerId) { diff --git a/src/components/App.tsx b/src/components/App.tsx index 714c349c8..624d4e346 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -260,13 +260,14 @@ import throttle from "lodash.throttle"; import { fileOpen, FileSystemHandle } from "../data/filesystem"; import { bindTextToShapeAfterDuplication, - getApproxLineHeight, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerDims, getContainerElement, + getDefaultLineHeight, + getLineHeightInPx, getTextBindableContainerAtPosition, isMeasureTextSupported, isValidTextContainer, @@ -1731,12 +1732,14 @@ class App extends React.Component { (acc: ExcalidrawTextElement[], line, idx) => { const text = line.trim(); + const lineHeight = getDefaultLineHeight(textElementProps.fontFamily); if (text.length) { const element = newTextElement({ ...textElementProps, x, y: currentY, text, + lineHeight, }); acc.push(element); currentY += element.height + LINE_GAP; @@ -1745,14 +1748,9 @@ class App extends React.Component { // add paragraph only if previous line was not empty, IOW don't add // more than one empty line if (prevLine) { - const defaultLineHeight = getApproxLineHeight( - getFontString({ - fontSize: textElementProps.fontSize, - fontFamily: textElementProps.fontFamily, - }), - ); - - currentY += defaultLineHeight + LINE_GAP; + currentY += + getLineHeightInPx(textElementProps.fontSize, lineHeight) + + LINE_GAP; } } @@ -2607,6 +2605,13 @@ class App extends React.Component { existingTextElement = this.getTextElementAtPosition(sceneX, sceneY); } + const fontFamily = + existingTextElement?.fontFamily || this.state.currentItemFontFamily; + + const lineHeight = + existingTextElement?.lineHeight || getDefaultLineHeight(fontFamily); + const fontSize = this.state.currentItemFontSize; + if ( !existingTextElement && shouldBindToContainer && @@ -2614,11 +2619,14 @@ class App extends React.Component { !isArrowElement(container) ) { const fontString = { - fontSize: this.state.currentItemFontSize, - fontFamily: this.state.currentItemFontFamily, + fontSize, + fontFamily, }; - const minWidth = getApproxMinLineWidth(getFontString(fontString)); - const minHeight = getApproxMinLineHeight(getFontString(fontString)); + const minWidth = getApproxMinLineWidth( + getFontString(fontString), + lineHeight, + ); + const minHeight = getApproxMinLineHeight(fontSize, lineHeight); const containerDims = getContainerDims(container); const newHeight = Math.max(containerDims.height, minHeight); const newWidth = Math.max(containerDims.width, minWidth); @@ -2652,8 +2660,8 @@ class App extends React.Component { opacity: this.state.currentItemOpacity, roundness: null, text: "", - fontSize: this.state.currentItemFontSize, - fontFamily: this.state.currentItemFontFamily, + fontSize, + fontFamily, textAlign: parentCenterPosition ? "center" : this.state.currentItemTextAlign, @@ -2663,6 +2671,7 @@ class App extends React.Component { containerId: shouldBindToContainer ? container?.id : undefined, groupIds: container?.groupIds ?? [], locked: false, + lineHeight, }); if (!existingTextElement && shouldBindToContainer && container) { diff --git a/src/data/restore.ts b/src/data/restore.ts index 98df4547b..270e06d98 100644 --- a/src/data/restore.ts +++ b/src/data/restore.ts @@ -35,6 +35,7 @@ import { getUpdatedTimestamp, updateActiveTool } from "../utils"; import { arrayToMap } from "../utils"; import oc from "open-color"; import { MarkOptional, Mutable } from "../utility-types"; +import { detectLineHeight, getDefaultLineHeight } from "../element/textElement"; type RestoredAppState = Omit< AppState, @@ -165,17 +166,32 @@ const restoreElement = ( const [fontPx, _fontFamily]: [string, string] = ( element as any ).font.split(" "); - fontSize = parseInt(fontPx, 10); + fontSize = parseFloat(fontPx); fontFamily = getFontFamilyByName(_fontFamily); } + const text = element.text ?? ""; + element = restoreElementWithProperties(element, { fontSize, fontFamily, - text: element.text ?? "", + text, textAlign: element.textAlign || DEFAULT_TEXT_ALIGN, verticalAlign: element.verticalAlign || DEFAULT_VERTICAL_ALIGN, containerId: element.containerId ?? null, - originalText: element.originalText || element.text, + originalText: element.originalText || text, + // line-height might not be specified either when creating elements + // programmatically, or when importing old diagrams. + // For the latter we want to detect the original line height which + // will likely differ from our per-font fixed line height we now use, + // to maintain backward compatibility. + lineHeight: + element.lineHeight || + (element.height + ? // detect line-height from current element height and font-size + detectLineHeight(element) + : // no element height likely means programmatic use, so default + // to a fixed line height + getDefaultLineHeight(element.fontFamily)), }); if (refreshDimensions) { diff --git a/src/element/newElement.ts b/src/element/newElement.ts index 0fe16b553..6581097cd 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -29,6 +29,7 @@ import { normalizeText, wrapText, getMaxContainerWidth, + getDefaultLineHeight, } from "./textElement"; import { VERTICAL_ALIGN } from "../constants"; import { isArrowElement } from "./typeChecks"; @@ -137,10 +138,12 @@ export const newTextElement = ( textAlign: TextAlign; verticalAlign: VerticalAlign; containerId?: ExcalidrawTextContainer["id"]; + lineHeight?: ExcalidrawTextElement["lineHeight"]; } & ElementConstructorOpts, ): NonDeleted => { + const lineHeight = opts.lineHeight || getDefaultLineHeight(opts.fontFamily); const text = normalizeText(opts.text); - const metrics = measureText(text, getFontString(opts)); + const metrics = measureText(text, getFontString(opts), lineHeight); const offsets = getTextElementPositionOffsets(opts, metrics); const textElement = newElementWith( { @@ -156,6 +159,7 @@ export const newTextElement = ( height: metrics.height, containerId: opts.containerId || null, originalText: text, + lineHeight, }, {}, ); @@ -176,6 +180,7 @@ const getAdjustedDimensions = ( const { width: nextWidth, height: nextHeight } = measureText( nextText, getFontString(element), + element.lineHeight, ); const { textAlign, verticalAlign } = element; let x: number; @@ -185,7 +190,11 @@ const getAdjustedDimensions = ( verticalAlign === VERTICAL_ALIGN.MIDDLE && !element.containerId ) { - const prevMetrics = measureText(element.text, getFontString(element)); + const prevMetrics = measureText( + element.text, + getFontString(element), + element.lineHeight, + ); const offsets = getTextElementPositionOffsets(element, { width: nextWidth - prevMetrics.width, height: nextHeight - prevMetrics.height, diff --git a/src/element/resizeElements.ts b/src/element/resizeElements.ts index 05eb630ed..a49559a7e 100644 --- a/src/element/resizeElements.ts +++ b/src/element/resizeElements.ts @@ -39,13 +39,13 @@ import { import { Point, PointerDownState } from "../types"; import Scene from "../scene/Scene"; import { - getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getBoundTextElementId, getContainerElement, handleBindTextResize, getMaxContainerWidth, + getApproxMinLineHeight, } from "./textElement"; export const normalizeAngle = (angle: number): number => { @@ -360,7 +360,7 @@ export const resizeSingleElement = ( let scaleX = atStartBoundsWidth / boundsCurrentWidth; let scaleY = atStartBoundsHeight / boundsCurrentHeight; - let boundTextFont: { fontSize?: number } = {}; + let boundTextFontSize: number | null = null; const boundTextElement = getBoundTextElement(element); if (transformHandleDirection.includes("e")) { @@ -410,9 +410,7 @@ export const resizeSingleElement = ( boundTextElement.id, ) as typeof boundTextElement | undefined; if (stateOfBoundTextElementAtResize) { - boundTextFont = { - fontSize: stateOfBoundTextElementAtResize.fontSize, - }; + boundTextFontSize = stateOfBoundTextElementAtResize.fontSize; } if (shouldMaintainAspectRatio) { const updatedElement = { @@ -428,12 +426,16 @@ export const resizeSingleElement = ( if (nextFontSize === null) { return; } - boundTextFont = { - fontSize: nextFontSize, - }; + boundTextFontSize = nextFontSize; } else { - const minWidth = getApproxMinLineWidth(getFontString(boundTextElement)); - const minHeight = getApproxMinLineHeight(getFontString(boundTextElement)); + const minWidth = getApproxMinLineWidth( + getFontString(boundTextElement), + boundTextElement.lineHeight, + ); + const minHeight = getApproxMinLineHeight( + boundTextElement.fontSize, + boundTextElement.lineHeight, + ); eleNewWidth = Math.ceil(Math.max(eleNewWidth, minWidth)); eleNewHeight = Math.ceil(Math.max(eleNewHeight, minHeight)); } @@ -566,8 +568,10 @@ export const resizeSingleElement = ( }); mutateElement(element, resizedElement); - if (boundTextElement && boundTextFont) { - mutateElement(boundTextElement, { fontSize: boundTextFont.fontSize }); + if (boundTextElement && boundTextFontSize != null) { + mutateElement(boundTextElement, { + fontSize: boundTextFontSize, + }); } handleBindTextResize(element, transformHandleDirection); } diff --git a/src/element/textElement.test.ts b/src/element/textElement.test.ts index be6d1a8a2..aa7df8ee6 100644 --- a/src/element/textElement.test.ts +++ b/src/element/textElement.test.ts @@ -1,4 +1,4 @@ -import { BOUND_TEXT_PADDING } from "../constants"; +import { BOUND_TEXT_PADDING, FONT_FAMILY } from "../constants"; import { API } from "../tests/helpers/api"; import { computeContainerDimensionForBoundText, @@ -6,6 +6,9 @@ import { getMaxContainerWidth, getMaxContainerHeight, wrapText, + detectLineHeight, + getLineHeightInPx, + getDefaultLineHeight, } from "./textElement"; import { FontString } from "./types"; @@ -40,9 +43,7 @@ describe("Test wrapText", () => { { desc: "break all words when width of each word is less than container width", width: 80, - res: `Hello -whats -up`, + res: `Hello \nwhats \nup`, }, { desc: "break all characters when width of each character is less than container width", @@ -64,8 +65,7 @@ p`, desc: "break words as per the width", width: 140, - res: `Hello whats -up`, + res: `Hello whats \nup`, }, { desc: "fit the container", @@ -95,9 +95,7 @@ whats up`; { desc: "break all words when width of each word is less than container width", width: 80, - res: `Hello -whats -up`, + res: `Hello\nwhats \nup`, }, { desc: "break all characters when width of each character is less than container width", @@ -143,11 +141,7 @@ whats up`, { desc: "fit characters of long string as per container width", width: 170, - res: `hellolongtextth -isiswhatsupwith -youIamtypingggg -gandtypinggg -break it now`, + res: `hellolongtextth\nisiswhatsupwith\nyouIamtypingggg\ngandtypinggg \nbreak it now`, }, { @@ -166,8 +160,7 @@ now`, desc: "fit the long text when container width is greater than text length and move the rest to next line", width: 600, - res: `hellolongtextthisiswhatsupwithyouIamtypingggggandtypinggg -break it now`, + res: `hellolongtextthisiswhatsupwithyouIamtypingggggandtypinggg \nbreak it now`, }, ].forEach((data) => { it(`should ${data.desc}`, () => { @@ -181,8 +174,7 @@ break it now`, const text = "Hello Excalidraw"; // Length of "Excalidraw" is 100 and exacty equal to max width const res = wrapText(text, font, 100); - expect(res).toEqual(`Hello -Excalidraw`); + expect(res).toEqual(`Hello \nExcalidraw`); }); it("should return the text as is if max width is invalid", () => { @@ -312,3 +304,35 @@ describe("Test measureText", () => { }); }); }); + +const textElement = API.createElement({ + type: "text", + text: "Excalidraw is a\nvirtual \nopensource \nwhiteboard for \nsketching \nhand-drawn like\ndiagrams", + fontSize: 20, + fontFamily: 1, + height: 175, +}); + +describe("Test detectLineHeight", () => { + it("should return correct line height", () => { + expect(detectLineHeight(textElement)).toBe(1.25); + }); +}); + +describe("Test getLineHeightInPx", () => { + it("should return correct line height", () => { + expect( + getLineHeightInPx(textElement.fontSize, textElement.lineHeight), + ).toBe(25); + }); +}); + +describe("Test getDefaultLineHeight", () => { + it("should return line height using default font family when not passed", () => { + //@ts-ignore + expect(getDefaultLineHeight()).toBe(1.25); + }); + it("should return correct line height", () => { + expect(getDefaultLineHeight(FONT_FAMILY.Cascadia)).toBe(1.2); + }); +}); diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 8d1b09014..fd501c141 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -4,6 +4,7 @@ import { ExcalidrawTextContainer, ExcalidrawTextElement, ExcalidrawTextElementWithContainer, + FontFamilyValues, FontString, NonDeletedExcalidrawElement, } from "./types"; @@ -12,6 +13,7 @@ import { BOUND_TEXT_PADDING, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, + FONT_FAMILY, TEXT_ALIGN, VERTICAL_ALIGN, } from "../constants"; @@ -41,12 +43,15 @@ export const normalizeText = (text: string) => { ); }; +export const splitIntoLines = (text: string) => { + return normalizeText(text).split("\n"); +}; + export const redrawTextBoundingBox = ( textElement: ExcalidrawTextElement, container: ExcalidrawElement | null, ) => { let maxWidth = undefined; - const boundTextUpdates = { x: textElement.x, y: textElement.y, @@ -68,6 +73,7 @@ export const redrawTextBoundingBox = ( const metrics = measureText( boundTextUpdates.text, getFontString(textElement), + textElement.lineHeight, ); boundTextUpdates.width = metrics.width; @@ -185,7 +191,11 @@ export const handleBindTextResize = ( maxWidth, ); } - const dimensions = measureText(text, getFontString(textElement)); + const dimensions = measureText( + text, + getFontString(textElement), + textElement.lineHeight, + ); nextHeight = dimensions.height; nextWidth = dimensions.width; } @@ -261,32 +271,52 @@ const computeBoundTextPosition = ( // https://github.com/grassator/canvas-text-editor/blob/master/lib/FontMetrics.js -export const measureText = (text: string, font: FontString) => { +export const measureText = ( + text: string, + font: FontString, + lineHeight: ExcalidrawTextElement["lineHeight"], +) => { text = text .split("\n") // replace empty lines with single space because leading/trailing empty // lines would be stripped from computation .map((x) => x || " ") .join("\n"); - - const height = getTextHeight(text, font); + const fontSize = parseFloat(font); + const height = getTextHeight(text, fontSize, lineHeight); const width = getTextWidth(text, font); return { width, height }; }; -const DUMMY_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toLocaleUpperCase(); -const cacheApproxLineHeight: { [key: FontString]: number } = {}; +/** + * To get unitless line-height (if unknown) we can calculate it by dividing + * height-per-line by fontSize. + */ +export const detectLineHeight = (textElement: ExcalidrawTextElement) => { + const lineCount = splitIntoLines(textElement.text).length; + return (textElement.height / + lineCount / + textElement.fontSize) as ExcalidrawTextElement["lineHeight"]; +}; -export const getApproxLineHeight = (font: FontString) => { - if (cacheApproxLineHeight[font]) { - return cacheApproxLineHeight[font]; - } - const fontSize = parseInt(font); +/** + * We calculate the line height from the font size and the unitless line height, + * aligning with the W3C spec. + */ +export const getLineHeightInPx = ( + fontSize: ExcalidrawTextElement["fontSize"], + lineHeight: ExcalidrawTextElement["lineHeight"], +) => { + return fontSize * lineHeight; +}; - // Calculate line height relative to font size - cacheApproxLineHeight[font] = fontSize * 1.2; - return cacheApproxLineHeight[font]; +// FIXME rename to getApproxMinContainerHeight +export const getApproxMinLineHeight = ( + fontSize: ExcalidrawTextElement["fontSize"], + lineHeight: ExcalidrawTextElement["lineHeight"], +) => { + return getLineHeightInPx(fontSize, lineHeight) + BOUND_TEXT_PADDING * 2; }; let canvas: HTMLCanvasElement | undefined; @@ -309,7 +339,7 @@ const getLineWidth = (text: string, font: FontString) => { }; export const getTextWidth = (text: string, font: FontString) => { - const lines = text.replace(/\r\n?/g, "\n").split("\n"); + const lines = splitIntoLines(text); let width = 0; lines.forEach((line) => { width = Math.max(width, getLineWidth(line, font)); @@ -317,10 +347,13 @@ export const getTextWidth = (text: string, font: FontString) => { return width; }; -export const getTextHeight = (text: string, font: FontString) => { - const lines = text.replace(/\r\n?/g, "\n").split("\n"); - const lineHeight = getApproxLineHeight(font); - return lineHeight * lines.length; +export const getTextHeight = ( + text: string, + fontSize: number, + lineHeight: ExcalidrawTextElement["lineHeight"], +) => { + const lineCount = splitIntoLines(text).length; + return getLineHeightInPx(fontSize, lineHeight) * lineCount; }; export const wrapText = (text: string, font: FontString, maxWidth: number) => { @@ -468,21 +501,23 @@ export const charWidth = (() => { }; })(); -export const getApproxMinLineWidth = (font: FontString) => { +const DUMMY_TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toLocaleUpperCase(); + +// FIXME rename to getApproxMinContainerWidth +export const getApproxMinLineWidth = ( + font: FontString, + lineHeight: ExcalidrawTextElement["lineHeight"], +) => { const maxCharWidth = getMaxCharWidth(font); if (maxCharWidth === 0) { return ( - measureText(DUMMY_TEXT.split("").join("\n"), font).width + + measureText(DUMMY_TEXT.split("").join("\n"), font, lineHeight).width + BOUND_TEXT_PADDING * 2 ); } return maxCharWidth + BOUND_TEXT_PADDING * 2; }; -export const getApproxMinLineHeight = (font: FontString) => { - return getApproxLineHeight(font) + BOUND_TEXT_PADDING * 2; -}; - export const getMinCharWidth = (font: FontString) => { const cache = charWidth.getCache(font); if (!cache) { @@ -828,3 +863,32 @@ export const isMeasureTextSupported = () => { ); return width > 0; }; + +/** + * Unitless line height + * + * In previous versions we used `normal` line height, which browsers interpret + * differently, and based on font-family and font-size. + * + * To make line heights consistent across browsers we hardcode the values for + * each of our fonts based on most common average line-heights. + * See https://github.com/excalidraw/excalidraw/pull/6360#issuecomment-1477635971 + * where the values come from. + */ +const DEFAULT_LINE_HEIGHT = { + // ~1.25 is the average for Virgil in WebKit and Blink. + // Gecko (FF) uses ~1.28. + [FONT_FAMILY.Virgil]: 1.25 as ExcalidrawTextElement["lineHeight"], + // ~1.15 is the average for Virgil in WebKit and Blink. + // Gecko if all over the place. + [FONT_FAMILY.Helvetica]: 1.15 as ExcalidrawTextElement["lineHeight"], + // ~1.2 is the average for Virgil in WebKit and Blink, and kinda Gecko too + [FONT_FAMILY.Cascadia]: 1.2 as ExcalidrawTextElement["lineHeight"], +}; + +export const getDefaultLineHeight = (fontFamily: FontFamilyValues) => { + if (fontFamily) { + return DEFAULT_LINE_HEIGHT[fontFamily]; + } + return DEFAULT_LINE_HEIGHT[DEFAULT_FONT_FAMILY]; +}; diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx index 25d266306..0873a2d23 100644 --- a/src/element/textWysiwyg.test.tsx +++ b/src/element/textWysiwyg.test.tsx @@ -783,7 +783,7 @@ describe("textWysiwyg", () => { rectangle.y + h.elements[0].height / 2 - text.height / 2, ); expect(text.x).toBe(25); - expect(text.height).toBe(48); + expect(text.height).toBe(50); expect(text.width).toBe(60); // Edit and text by removing second line and it should @@ -810,7 +810,7 @@ describe("textWysiwyg", () => { expect(text.text).toBe("Hello"); expect(text.originalText).toBe("Hello"); - expect(text.height).toBe(24); + expect(text.height).toBe(25); expect(text.width).toBe(50); expect(text.y).toBe( rectangle.y + h.elements[0].height / 2 - text.height / 2, @@ -903,7 +903,7 @@ describe("textWysiwyg", () => { expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(` Array [ 85, - 5, + 4.5, ] `); @@ -929,7 +929,7 @@ describe("textWysiwyg", () => { expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(` Array [ 15, - 66, + 65, ] `); @@ -1067,9 +1067,9 @@ describe("textWysiwyg", () => { mouse.moveTo(rectangle.x + 100, rectangle.y + 50); mouse.up(rectangle.x + 100, rectangle.y + 50); expect(rectangle.x).toBe(80); - expect(rectangle.y).toBe(-35); + expect(rectangle.y).toBe(-40); expect(text.x).toBe(85); - expect(text.y).toBe(-30); + expect(text.y).toBe(-35); Keyboard.withModifierKeys({ ctrl: true }, () => { Keyboard.keyPress(KEYS.Z); @@ -1112,7 +1112,7 @@ describe("textWysiwyg", () => { target: { value: "Online whiteboard collaboration made easy" }, }); editor.blur(); - expect(rectangle.height).toBe(178); + expect(rectangle.height).toBe(185); mouse.select(rectangle); fireEvent.contextMenu(GlobalTestState.canvas, { button: 2, @@ -1186,6 +1186,41 @@ describe("textWysiwyg", () => { ); }); + it("should update line height when font family updated", async () => { + Keyboard.keyPress(KEYS.ENTER); + expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75); + + const editor = document.querySelector( + ".excalidraw-textEditorContainer > textarea", + ) as HTMLTextAreaElement; + + await new Promise((r) => setTimeout(r, 0)); + fireEvent.change(editor, { target: { value: "Hello World!" } }); + editor.blur(); + expect( + (h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight, + ).toEqual(1.25); + + mouse.select(rectangle); + Keyboard.keyPress(KEYS.ENTER); + + fireEvent.click(screen.getByTitle(/code/i)); + expect( + (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily, + ).toEqual(FONT_FAMILY.Cascadia); + expect( + (h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight, + ).toEqual(1.2); + + fireEvent.click(screen.getByTitle(/normal/i)); + expect( + (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily, + ).toEqual(FONT_FAMILY.Helvetica); + expect( + (h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight, + ).toEqual(1.15); + }); + describe("should align correctly", () => { let editor: HTMLTextAreaElement; @@ -1245,7 +1280,7 @@ describe("textWysiwyg", () => { expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(` Array [ 15, - 45.5, + 45, ] `); }); @@ -1257,7 +1292,7 @@ describe("textWysiwyg", () => { expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(` Array [ 30, - 45.5, + 45, ] `); }); @@ -1269,7 +1304,7 @@ describe("textWysiwyg", () => { expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(` Array [ 45, - 45.5, + 45, ] `); }); @@ -1281,7 +1316,7 @@ describe("textWysiwyg", () => { expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(` Array [ 15, - 66, + 65, ] `); }); @@ -1292,7 +1327,7 @@ describe("textWysiwyg", () => { expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(` Array [ 30, - 66, + 65, ] `); }); @@ -1303,7 +1338,7 @@ describe("textWysiwyg", () => { expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(` Array [ 45, - 66, + 65, ] `); }); @@ -1333,7 +1368,7 @@ describe("textWysiwyg", () => { const textElement = h.elements[1] as ExcalidrawTextElement; expect(textElement.width).toBe(600); - expect(textElement.height).toBe(24); + expect(textElement.height).toBe(25); expect(textElement.textAlign).toBe(TEXT_ALIGN.LEFT); expect((textElement as ExcalidrawTextElement).text).toBe( "Excalidraw is an opensource virtual collaborative whiteboard", @@ -1365,7 +1400,7 @@ describe("textWysiwyg", () => { ], fillStyle: "hachure", groupIds: [], - height: 34, + height: 35, isDeleted: false, link: null, locked: false, diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index e2810e81d..4036719df 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -22,7 +22,6 @@ import { import { AppState } from "../types"; import { mutateElement } from "./mutateElement"; import { - getApproxLineHeight, getBoundTextElementId, getContainerCoords, getContainerDims, @@ -150,9 +149,7 @@ export const textWysiwyg = ({ return; } const { textAlign, verticalAlign } = updatedTextElement; - const approxLineHeight = getApproxLineHeight( - getFontString(updatedTextElement), - ); + if (updatedTextElement && isTextElement(updatedTextElement)) { let coordX = updatedTextElement.x; let coordY = updatedTextElement.y; @@ -213,7 +210,7 @@ export const textWysiwyg = ({ if (!isArrowElement(container) && textElementHeight > maxHeight) { const diff = Math.min( textElementHeight - maxHeight, - approxLineHeight, + element.lineHeight, ); mutateElement(container, { height: containerDims.height + diff }); return; @@ -226,7 +223,7 @@ export const textWysiwyg = ({ ) { const diff = Math.min( maxHeight - textElementHeight, - approxLineHeight, + element.lineHeight, ); mutateElement(container, { height: containerDims.height - diff }); } @@ -266,10 +263,6 @@ export const textWysiwyg = ({ editable.selectionEnd = editable.value.length - diff; } - const lines = updatedTextElement.originalText.split("\n"); - const lineHeight = updatedTextElement.containerId - ? approxLineHeight - : updatedTextElement.height / lines.length; if (!container) { maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value; textElementWidth = Math.min(textElementWidth, maxWidth); @@ -282,7 +275,7 @@ export const textWysiwyg = ({ Object.assign(editable.style, { font: getFontString(updatedTextElement), // must be defined *after* font ¯\_(ツ)_/¯ - lineHeight: `${lineHeight}px`, + lineHeight: element.lineHeight, width: `${textElementWidth}px`, height: `${textElementHeight}px`, left: `${viewportX}px`, @@ -388,7 +381,11 @@ export const textWysiwyg = ({ font, getMaxContainerWidth(container!), ); - const { width, height } = measureText(wrappedText, font); + const { width, height } = measureText( + wrappedText, + font, + updatedTextElement.lineHeight, + ); editable.style.width = `${width}px`; editable.style.height = `${height}px`; } diff --git a/src/element/types.ts b/src/element/types.ts index e99b7e897..4b4bad74e 100644 --- a/src/element/types.ts +++ b/src/element/types.ts @@ -135,6 +135,11 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase & verticalAlign: VerticalAlign; containerId: ExcalidrawGenericElement["id"] | null; originalText: string; + /** + * Unitless line height (aligned to W3C). To get line height in px, multiply + * with font size (using `getLineHeightInPx` helper). + */ + lineHeight: number & { _brand: "unitlessLineHeight" }; }>; export type ExcalidrawBindableElement = diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index e49a1f465..0861315cc 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -40,10 +40,10 @@ import { } from "../constants"; import { getStroke, StrokeOptions } from "perfect-freehand"; import { - getApproxLineHeight, getBoundTextElement, getContainerCoords, getContainerElement, + getLineHeightInPx, getMaxContainerHeight, getMaxContainerWidth, } from "../element/textElement"; @@ -279,9 +279,7 @@ const drawElementOnCanvas = ( // Canvas does not support multiline text by default const lines = element.text.replace(/\r\n?/g, "\n").split("\n"); - const lineHeight = element.containerId - ? getApproxLineHeight(getFontString(element)) - : element.height / lines.length; + const horizontalOffset = element.textAlign === "center" ? element.width / 2 @@ -290,11 +288,16 @@ const drawElementOnCanvas = ( : 0; context.textBaseline = "bottom"; + const lineHeightPx = getLineHeightInPx( + element.fontSize, + element.lineHeight, + ); + for (let index = 0; index < lines.length; index++) { context.fillText( lines[index], horizontalOffset, - (index + 1) * lineHeight, + (index + 1) * lineHeightPx, ); } context.restore(); @@ -1313,7 +1316,10 @@ export const renderElementToSvg = ( }) rotate(${degree} ${cx} ${cy})`, ); const lines = element.text.replace(/\r\n?/g, "\n").split("\n"); - const lineHeight = element.height / lines.length; + const lineHeightPx = getLineHeightInPx( + element.fontSize, + element.lineHeight, + ); const horizontalOffset = element.textAlign === "center" ? element.width / 2 @@ -1331,7 +1337,7 @@ export const renderElementToSvg = ( const text = svgRoot.ownerDocument!.createElementNS(SVG_NS, "text"); text.textContent = lines[i]; text.setAttribute("x", `${horizontalOffset}`); - text.setAttribute("y", `${i * lineHeight}`); + text.setAttribute("y", `${i * lineHeightPx}`); text.setAttribute("font-family", getFontFamilyString(element)); text.setAttribute("font-size", `${element.fontSize}px`); text.setAttribute("fill", element.strokeColor); diff --git a/src/tests/__snapshots__/linearElementEditor.test.tsx.snap b/src/tests/__snapshots__/linearElementEditor.test.tsx.snap index f84eab3a2..a2f142b66 100644 --- a/src/tests/__snapshots__/linearElementEditor.test.tsx.snap +++ b/src/tests/__snapshots__/linearElementEditor.test.tsx.snap @@ -5,7 +5,7 @@ exports[`Test Linear Elements Test bound text element should match styles for te class="excalidraw-wysiwyg" data-type="wysiwyg" dir="auto" - style="position: absolute; display: inline-block; min-height: 1em; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 24px; left: 35px; top: 8px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(0, 0, 0); opacity: 1; filter: var(--theme-filter); max-height: -8px; font: Emoji 20px 20px; line-height: 24px; font-family: Virgil, Segoe UI Emoji;" + style="position: absolute; display: inline-block; min-height: 1em; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 25px; left: 35px; top: 7.5px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(0, 0, 0); opacity: 1; filter: var(--theme-filter); max-height: -7.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Virgil, Segoe UI Emoji;" tabindex="0" wrap="off" /> diff --git a/src/tests/clipboard.test.tsx b/src/tests/clipboard.test.tsx index 26fcf4f0b..1fdc0f452 100644 --- a/src/tests/clipboard.test.tsx +++ b/src/tests/clipboard.test.tsx @@ -3,8 +3,10 @@ import { render, waitFor, GlobalTestState } from "./test-utils"; import { Pointer, Keyboard } from "./helpers/ui"; import ExcalidrawApp from "../excalidraw-app"; import { KEYS } from "../keys"; -import { getApproxLineHeight } from "../element/textElement"; -import { getFontString } from "../utils"; +import { + getDefaultLineHeight, + getLineHeightInPx, +} from "../element/textElement"; import { getElementBounds } from "../element"; import { NormalizedZoomValue } from "../types"; @@ -118,12 +120,10 @@ describe("paste text as single lines", () => { it("should space items correctly", async () => { const text = "hkhkjhki\njgkjhffjh\njgkjhffjh"; - const lineHeight = - getApproxLineHeight( - getFontString({ - fontSize: h.app.state.currentItemFontSize, - fontFamily: h.app.state.currentItemFontFamily, - }), + const lineHeightPx = + getLineHeightInPx( + h.app.state.currentItemFontSize, + getDefaultLineHeight(h.state.currentItemFontFamily), ) + 10 / h.app.state.zoom.value; mouse.moveTo(100, 100); @@ -135,19 +135,17 @@ describe("paste text as single lines", () => { for (let i = 1; i < h.elements.length; i++) { // eslint-disable-next-line @typescript-eslint/no-unused-vars const [fx, elY] = getElementBounds(h.elements[i]); - expect(elY).toEqual(firstElY + lineHeight * i); + expect(elY).toEqual(firstElY + lineHeightPx * i); } }); }); it("should leave a space for blank new lines", async () => { const text = "hkhkjhki\n\njgkjhffjh"; - const lineHeight = - getApproxLineHeight( - getFontString({ - fontSize: h.app.state.currentItemFontSize, - fontFamily: h.app.state.currentItemFontFamily, - }), + const lineHeightPx = + getLineHeightInPx( + h.app.state.currentItemFontSize, + getDefaultLineHeight(h.state.currentItemFontFamily), ) + 10 / h.app.state.zoom.value; mouse.moveTo(100, 100); @@ -158,7 +156,7 @@ describe("paste text as single lines", () => { const [fx, firstElY] = getElementBounds(h.elements[0]); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [lx, lastElY] = getElementBounds(h.elements[1]); - expect(lastElY).toEqual(firstElY + lineHeight * 2); + expect(lastElY).toEqual(firstElY + lineHeightPx * 2); }); }); }); @@ -224,7 +222,7 @@ describe("Paste bound text container", () => { await sleep(1); expect(h.elements.length).toEqual(2); const container = h.elements[0]; - expect(container.height).toBe(354); + expect(container.height).toBe(368); expect(container.width).toBe(166); }); }); @@ -247,7 +245,7 @@ describe("Paste bound text container", () => { await sleep(1); expect(h.elements.length).toEqual(2); const container = h.elements[0]; - expect(container.height).toBe(740); + expect(container.height).toBe(770); expect(container.width).toBe(166); }); }); diff --git a/src/tests/data/__snapshots__/restore.test.ts.snap b/src/tests/data/__snapshots__/restore.test.ts.snap index b88803cd4..e9a0da005 100644 --- a/src/tests/data/__snapshots__/restore.test.ts.snap +++ b/src/tests/data/__snapshots__/restore.test.ts.snap @@ -291,6 +291,7 @@ Object { "height": 100, "id": "id-text01", "isDeleted": false, + "lineHeight": 1.25, "link": null, "locked": false, "opacity": 100, @@ -312,7 +313,7 @@ Object { "verticalAlign": "middle", "width": 100, "x": -20, - "y": -8.4, + "y": -8.75, } `; @@ -329,6 +330,7 @@ Object { "height": 100, "id": "id-text01", "isDeleted": false, + "lineHeight": 1.25, "link": null, "locked": false, "opacity": 100, diff --git a/src/tests/helpers/api.ts b/src/tests/helpers/api.ts index 5cd0943ae..bc8bfc8a9 100644 --- a/src/tests/helpers/api.ts +++ b/src/tests/helpers/api.ts @@ -181,11 +181,13 @@ export class API { }); break; case "text": + const fontSize = rest.fontSize ?? appState.currentItemFontSize; + const fontFamily = rest.fontFamily ?? appState.currentItemFontFamily; element = newTextElement({ ...base, text: rest.text || "test", - fontSize: rest.fontSize ?? appState.currentItemFontSize, - fontFamily: rest.fontFamily ?? appState.currentItemFontFamily, + fontSize, + fontFamily, textAlign: rest.textAlign ?? appState.currentItemTextAlign, verticalAlign: rest.verticalAlign ?? DEFAULT_VERTICAL_ALIGN, containerId: rest.containerId ?? undefined, diff --git a/src/tests/linearElementEditor.test.tsx b/src/tests/linearElementEditor.test.tsx index 8c1d29325..ac4d801bc 100644 --- a/src/tests/linearElementEditor.test.tsx +++ b/src/tests/linearElementEditor.test.tsx @@ -1031,7 +1031,7 @@ describe("Test Linear Elements", () => { expect({ width: container.width, height: container.height }) .toMatchInlineSnapshot(` Object { - "height": 128, + "height": 130, "width": 367, } `); @@ -1040,7 +1040,7 @@ describe("Test Linear Elements", () => { .toMatchInlineSnapshot(` Object { "x": 272, - "y": 46, + "y": 45, } `); expect((h.elements[1] as ExcalidrawTextElementWithContainer).text) @@ -1052,11 +1052,11 @@ describe("Test Linear Elements", () => { .toMatchInlineSnapshot(` Array [ 20, - 36, + 35, 502, - 94, + 95, 205.9061448421403, - 53, + 52.5, ] `); }); @@ -1090,7 +1090,7 @@ describe("Test Linear Elements", () => { expect({ width: container.width, height: container.height }) .toMatchInlineSnapshot(` Object { - "height": 128, + "height": 130, "width": 340, } `); @@ -1099,7 +1099,7 @@ describe("Test Linear Elements", () => { .toMatchInlineSnapshot(` Object { "x": 75, - "y": -4, + "y": -5, } `); expect(textElement.text).toMatchInlineSnapshot(` From 9e52c30ce86d7f7e61ffdb5ecad2523e179f620e Mon Sep 17 00:00:00 2001 From: David Luzar Date: Wed, 22 Mar 2023 18:33:37 +0100 Subject: [PATCH 003/451] fix: use `ideographic` textBaseline to improve layout shift when editing text (#6384) --- src/renderer/renderElement.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index 0861315cc..66d2096cf 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -34,6 +34,7 @@ import { AppState, BinaryFiles, Zoom } from "../types"; import { getDefaultAppState } from "../appState"; import { BOUND_TEXT_PADDING, + FONT_FAMILY, MAX_DECIMALS_FOR_SVG_EXPORT, MIME_TYPES, SVG_NS, @@ -286,7 +287,13 @@ const drawElementOnCanvas = ( : element.textAlign === "right" ? element.width : 0; - context.textBaseline = "bottom"; + + // FIXME temporary hack + context.textBaseline = + element.fontFamily === FONT_FAMILY.Virgil || + element.fontFamily === FONT_FAMILY.Cascadia + ? "ideographic" + : "bottom"; const lineHeightPx = getLineHeightInPx( element.fontSize, From 25bb6738ea8619021b27e072fa7707e1b6356c7b Mon Sep 17 00:00:00 2001 From: Type Horror Date: Sat, 25 Mar 2023 15:26:58 -0700 Subject: [PATCH 004/451] feat: Add fitToContent and animate to scrollToContent (#6319) Co-authored-by: Brice Leroy Co-authored-by: dwelle --- .../@excalidraw/excalidraw/api/props/ref.mdx | 66 ++++-- src/actions/actionCanvas.tsx | 2 +- src/components/App.tsx | 115 +++++++++-- src/data/restore.ts | 4 +- src/packages/excalidraw/CHANGELOG.md | 2 + src/tests/fitToContent.test.tsx | 189 ++++++++++++++++++ src/utils.ts | 73 +++++++ 7 files changed, 413 insertions(+), 38 deletions(-) create mode 100644 src/tests/fitToContent.test.tsx diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/props/ref.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/props/ref.mdx index a37843c76..08e807907 100644 --- a/dev-docs/docs/@excalidraw/excalidraw/api/props/ref.mdx +++ b/dev-docs/docs/@excalidraw/excalidraw/api/props/ref.mdx @@ -1,6 +1,19 @@ # ref +
-createRef | useRef | callbackRef | 
{ current: { readyPromise: resolvablePromise } } + + createRef + {" "} + |{" "} + useRef{" "} + |{" "} + + callbackRef + {" "} + |
+ { current: { readyPromise: + resolvablePromise + } }
You can pass a `ref` when you want to access some excalidraw APIs. We expose the below APIs: @@ -139,7 +152,9 @@ function App() { return (

Click to update the scene

- + setExcalidrawAPI(api)} />
); @@ -187,7 +202,8 @@ function App() { return (

Click to update the library items

-

From 0b8fc4f4b62a48e432b3fd6b1b97c5a4334f4792 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Mon, 10 Apr 2023 16:31:58 +0530 Subject: [PATCH 013/451] fix: don't refresh dimensions for deleted text elements (#6438) --- src/element/newElement.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/element/newElement.ts b/src/element/newElement.ts index 6581097cd..b08bac92c 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -265,6 +265,9 @@ export const refreshTextDimensions = ( textElement: ExcalidrawTextElement, text = textElement.text, ) => { + if (textElement.isDeleted) { + return; + } const container = getContainerElement(textElement); if (container) { text = wrapText( From ec215362a1723ad9749e70aece84358add20ce94 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Mon, 10 Apr 2023 18:52:46 +0530 Subject: [PATCH 014/451] fix: introduce baseline to fix the layout shift when switching to text editor (#6397) * fix: introduce baseline to fix the layout shift when switching to text editor * uncomment * change offset to 8pixels * [debug] * introduce DOM baseline in canvas rendering instead * introduce baseline in element making it backward compat * fix * lint * fix * update baseline when resizing text element * fix safari backward compat * fix for safari * lint * reduce safari LS * floor line height and height when dom height increases than canvas height * Revert "floor line height and height when dom height increases than canvas height" This reverts commit 8de65168238b8fb9a638e0c75f596f371983c2c7. * cleanup * use DOM height only for safari to fix LS * Revert "use DOM height only for safari to fix LS" This reverts commit d75889238da59b7954ec3a6ac2c29dc0ba420635. * fix lint and test * fix * calculate line height by rounding off instead of DOM * cleanup --------- Co-authored-by: dwelle --- src/actions/actionBoundText.tsx | 3 +- src/data/restore.ts | 42 +++++++----- src/element/newElement.ts | 14 ++-- src/element/resizeElements.ts | 61 ++++++++++++----- src/element/textElement.ts | 65 +++++++++++++++++-- src/element/textWysiwyg.tsx | 16 ++++- src/element/types.ts | 1 + src/renderer/renderElement.ts | 7 +- .../data/__snapshots__/restore.test.ts.snap | 2 + 9 files changed, 161 insertions(+), 50 deletions(-) diff --git a/src/actions/actionBoundText.tsx b/src/actions/actionBoundText.tsx index 4cc72d612..9f9fbfc0f 100644 --- a/src/actions/actionBoundText.tsx +++ b/src/actions/actionBoundText.tsx @@ -43,7 +43,7 @@ export const actionUnbindText = register({ selectedElements.forEach((element) => { const boundTextElement = getBoundTextElement(element); if (boundTextElement) { - const { width, height } = measureText( + const { width, height, baseline } = measureText( boundTextElement.originalText, getFontString(boundTextElement), boundTextElement.lineHeight, @@ -57,6 +57,7 @@ export const actionUnbindText = register({ containerId: null, width, height, + baseline, text: boundTextElement.originalText, }); mutateElement(element, { diff --git a/src/data/restore.ts b/src/data/restore.ts index 57ea329c3..2735d91d2 100644 --- a/src/data/restore.ts +++ b/src/data/restore.ts @@ -31,11 +31,15 @@ import { import { getDefaultAppState } from "../appState"; import { LinearElementEditor } from "../element/linearElementEditor"; import { bumpVersion } from "../element/mutateElement"; -import { getUpdatedTimestamp, updateActiveTool } from "../utils"; +import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils"; import { arrayToMap } from "../utils"; import oc from "open-color"; import { MarkOptional, Mutable } from "../utility-types"; -import { detectLineHeight, getDefaultLineHeight } from "../element/textElement"; +import { + detectLineHeight, + getDefaultLineHeight, + measureBaseline, +} from "../element/textElement"; type RestoredAppState = Omit< AppState, @@ -171,6 +175,24 @@ const restoreElement = ( } const text = element.text ?? ""; + // line-height might not be specified either when creating elements + // programmatically, or when importing old diagrams. + // For the latter we want to detect the original line height which + // will likely differ from our per-font fixed line height we now use, + // to maintain backward compatibility. + const lineHeight = + element.lineHeight || + (element.height + ? // detect line-height from current element height and font-size + detectLineHeight(element) + : // no element height likely means programmatic use, so default + // to a fixed line height + getDefaultLineHeight(element.fontFamily)); + const baseline = measureBaseline( + element.text, + getFontString(element), + lineHeight, + ); element = restoreElementWithProperties(element, { fontSize, fontFamily, @@ -179,19 +201,9 @@ const restoreElement = ( verticalAlign: element.verticalAlign || DEFAULT_VERTICAL_ALIGN, containerId: element.containerId ?? null, originalText: element.originalText || text, - // line-height might not be specified either when creating elements - // programmatically, or when importing old diagrams. - // For the latter we want to detect the original line height which - // will likely differ from our per-font fixed line height we now use, - // to maintain backward compatibility. - lineHeight: - element.lineHeight || - (element.height - ? // detect line-height from current element height and font-size - detectLineHeight(element) - : // no element height likely means programmatic use, so default - // to a fixed line height - getDefaultLineHeight(element.fontFamily)), + + lineHeight, + baseline, }); if (refreshDimensions) { diff --git a/src/element/newElement.ts b/src/element/newElement.ts index b08bac92c..b6b6cad2d 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -145,6 +145,7 @@ export const newTextElement = ( const text = normalizeText(opts.text); const metrics = measureText(text, getFontString(opts), lineHeight); const offsets = getTextElementPositionOffsets(opts, metrics); + const textElement = newElementWith( { ..._newElementBase("text", opts), @@ -157,6 +158,7 @@ export const newTextElement = ( y: opts.y - offsets.y, width: metrics.width, height: metrics.height, + baseline: metrics.baseline, containerId: opts.containerId || null, originalText: text, lineHeight, @@ -174,14 +176,15 @@ const getAdjustedDimensions = ( y: number; width: number; height: number; + baseline: number; } => { const container = getContainerElement(element); - const { width: nextWidth, height: nextHeight } = measureText( - nextText, - getFontString(element), - element.lineHeight, - ); + const { + width: nextWidth, + height: nextHeight, + baseline: nextBaseline, + } = measureText(nextText, getFontString(element), element.lineHeight); const { textAlign, verticalAlign } = element; let x: number; let y: number; @@ -256,6 +259,7 @@ const getAdjustedDimensions = ( return { width: nextWidth, height: nextHeight, + baseline: nextBaseline, x: Number.isFinite(x) ? x : element.x, y: Number.isFinite(y) ? y : element.y, }; diff --git a/src/element/resizeElements.ts b/src/element/resizeElements.ts index a49559a7e..69b8afae7 100644 --- a/src/element/resizeElements.ts +++ b/src/element/resizeElements.ts @@ -46,6 +46,8 @@ import { handleBindTextResize, getMaxContainerWidth, getApproxMinLineHeight, + measureText, + getMaxContainerHeight, } from "./textElement"; export const normalizeAngle = (angle: number): number => { @@ -193,7 +195,8 @@ const MIN_FONT_SIZE = 1; const measureFontSizeFromWidth = ( element: NonDeleted, nextWidth: number, -): number | null => { + nextHeight: number, +): { size: number; baseline: number } | null => { // We only use width to scale font on resize let width = element.width; @@ -208,8 +211,15 @@ const measureFontSizeFromWidth = ( if (nextFontSize < MIN_FONT_SIZE) { return null; } - - return nextFontSize; + const metrics = measureText( + element.text, + getFontString({ fontSize: nextFontSize, fontFamily: element.fontFamily }), + element.lineHeight, + ); + return { + size: nextFontSize, + baseline: metrics.baseline + (nextHeight - metrics.height), + }; }; const getSidesForTransformHandle = ( @@ -280,8 +290,8 @@ const resizeSingleTextElement = ( if (scale > 0) { const nextWidth = element.width * scale; const nextHeight = element.height * scale; - const nextFontSize = measureFontSizeFromWidth(element, nextWidth); - if (nextFontSize === null) { + const metrics = measureFontSizeFromWidth(element, nextWidth, nextHeight); + if (metrics === null) { return; } const [nextX1, nextY1, nextX2, nextY2] = getResizedElementAbsoluteCoords( @@ -305,9 +315,10 @@ const resizeSingleTextElement = ( deltaY2, ); mutateElement(element, { - fontSize: nextFontSize, + fontSize: metrics.size, width: nextWidth, height: nextHeight, + baseline: metrics.baseline, x: nextElementX, y: nextElementY, }); @@ -360,7 +371,7 @@ export const resizeSingleElement = ( let scaleX = atStartBoundsWidth / boundsCurrentWidth; let scaleY = atStartBoundsHeight / boundsCurrentHeight; - let boundTextFontSize: number | null = null; + let boundTextFont: { fontSize?: number; baseline?: number } = {}; const boundTextElement = getBoundTextElement(element); if (transformHandleDirection.includes("e")) { @@ -410,7 +421,10 @@ export const resizeSingleElement = ( boundTextElement.id, ) as typeof boundTextElement | undefined; if (stateOfBoundTextElementAtResize) { - boundTextFontSize = stateOfBoundTextElementAtResize.fontSize; + boundTextFont = { + fontSize: stateOfBoundTextElementAtResize.fontSize, + baseline: stateOfBoundTextElementAtResize.baseline, + }; } if (shouldMaintainAspectRatio) { const updatedElement = { @@ -419,14 +433,18 @@ export const resizeSingleElement = ( height: eleNewHeight, }; - const nextFontSize = measureFontSizeFromWidth( + const nextFont = measureFontSizeFromWidth( boundTextElement, getMaxContainerWidth(updatedElement), + getMaxContainerHeight(updatedElement), ); - if (nextFontSize === null) { + if (nextFont === null) { return; } - boundTextFontSize = nextFontSize; + boundTextFont = { + fontSize: nextFont.size, + baseline: nextFont.baseline, + }; } else { const minWidth = getApproxMinLineWidth( getFontString(boundTextElement), @@ -568,9 +586,10 @@ export const resizeSingleElement = ( }); mutateElement(element, resizedElement); - if (boundTextElement && boundTextFontSize != null) { + if (boundTextElement && boundTextFont != null) { mutateElement(boundTextElement, { - fontSize: boundTextFontSize, + fontSize: boundTextFont.fontSize, + baseline: boundTextFont.baseline, }); } handleBindTextResize(element, transformHandleDirection); @@ -677,6 +696,7 @@ const resizeMultipleElements = ( y: number; points?: Point[]; fontSize?: number; + baseline?: number; } = { width, height, @@ -685,7 +705,7 @@ const resizeMultipleElements = ( ...rescaledPoints, }; - let boundTextUpdates: { fontSize: number } | null = null; + let boundTextUpdates: { fontSize: number; baseline: number } | null = null; const boundTextElement = getBoundTextElement(element.latest); @@ -695,24 +715,29 @@ const resizeMultipleElements = ( width, height, }; - const fontSize = measureFontSizeFromWidth( + const metrics = measureFontSizeFromWidth( boundTextElement ?? (element.orig as ExcalidrawTextElement), boundTextElement ? getMaxContainerWidth(updatedElement) : updatedElement.width, + boundTextElement + ? getMaxContainerHeight(updatedElement) + : updatedElement.height, ); - if (!fontSize) { + if (!metrics) { return; } if (isTextElement(element.orig)) { - update.fontSize = fontSize; + update.fontSize = metrics.size; + update.baseline = metrics.baseline; } if (boundTextElement) { boundTextUpdates = { - fontSize, + fontSize: metrics.size, + baseline: metrics.baseline, }; } } diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 8b3979133..26cf91a89 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -14,6 +14,7 @@ import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, FONT_FAMILY, + isSafari, TEXT_ALIGN, VERTICAL_ALIGN, } from "../constants"; @@ -58,6 +59,7 @@ export const redrawTextBoundingBox = ( text: textElement.text, width: textElement.width, height: textElement.height, + baseline: textElement.baseline, }; boundTextUpdates.text = textElement.text; @@ -78,6 +80,7 @@ export const redrawTextBoundingBox = ( boundTextUpdates.width = metrics.width; boundTextUpdates.height = metrics.height; + boundTextUpdates.baseline = metrics.baseline; if (container) { if (isArrowElement(container)) { @@ -183,6 +186,7 @@ export const handleBindTextResize = ( const maxWidth = getMaxContainerWidth(container); const maxHeight = getMaxContainerHeight(container); let containerHeight = containerDims.height; + let nextBaseLine = textElement.baseline; if (transformHandleType !== "n" && transformHandleType !== "s") { if (text) { text = wrapText( @@ -191,13 +195,14 @@ export const handleBindTextResize = ( maxWidth, ); } - const dimensions = measureText( + const metrics = measureText( text, getFontString(textElement), textElement.lineHeight, ); - nextHeight = dimensions.height; - nextWidth = dimensions.width; + nextHeight = metrics.height; + nextWidth = metrics.width; + nextBaseLine = metrics.baseline; } // increase height in case text element height exceeds if (nextHeight > maxHeight) { @@ -225,6 +230,7 @@ export const handleBindTextResize = ( text, width: nextWidth, height: nextHeight, + baseline: nextBaseLine, }); if (!isArrowElement(container)) { @@ -285,8 +291,59 @@ export const measureText = ( const fontSize = parseFloat(font); const height = getTextHeight(text, fontSize, lineHeight); const width = getTextWidth(text, font); + const baseline = measureBaseline(text, font, lineHeight); + return { width, height, baseline }; +}; - return { width, height }; +export const measureBaseline = ( + text: string, + font: FontString, + lineHeight: ExcalidrawTextElement["lineHeight"], + wrapInContainer?: boolean, +) => { + const container = document.createElement("div"); + container.style.position = "absolute"; + container.style.whiteSpace = "pre"; + container.style.font = font; + container.style.minHeight = "1em"; + if (wrapInContainer) { + container.style.overflow = "hidden"; + container.style.wordBreak = "break-word"; + container.style.whiteSpace = "pre-wrap"; + } + + container.style.lineHeight = String(lineHeight); + + container.innerText = text; + + // Baseline is important for positioning text on canvas + document.body.appendChild(container); + + const span = document.createElement("span"); + span.style.display = "inline-block"; + span.style.overflow = "hidden"; + span.style.width = "1px"; + span.style.height = "1px"; + container.appendChild(span); + let baseline = span.offsetTop + span.offsetHeight; + const height = container.offsetHeight; + + if (isSafari) { + const canvasHeight = getTextHeight(text, parseFloat(font), lineHeight); + const fontSize = parseFloat(font); + // In Safari the font size gets rounded off when rendering hence calculating the safari height and shifting the baseline if it differs + // from the actual canvas height + const domHeight = getTextHeight(text, Math.round(fontSize), lineHeight); + if (canvasHeight > height) { + baseline += canvasHeight - domHeight; + } + + if (height > canvasHeight) { + baseline -= domHeight - canvasHeight; + } + } + document.body.removeChild(container); + return baseline; }; /** diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index 4e8ef3a5c..ef4f7c926 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -11,7 +11,7 @@ import { isBoundToContainer, isTextElement, } from "./typeChecks"; -import { CLASSES, VERTICAL_ALIGN } from "../constants"; +import { CLASSES, isSafari, VERTICAL_ALIGN } from "../constants"; import { ExcalidrawElement, ExcalidrawLinearElement, @@ -35,6 +35,7 @@ import { getMaxContainerHeight, getMaxContainerWidth, computeContainerDimensionForBoundText, + detectLineHeight, } from "./textElement"; import { actionDecreaseFontSize, @@ -271,13 +272,24 @@ export const textWysiwyg = ({ } else { textElementWidth += 0.5; } + + let lineHeight = updatedTextElement.lineHeight; + + // In Safari the font size gets rounded off when rendering hence calculating the line height by rounding off font size + if (isSafari) { + lineHeight = detectLineHeight({ + ...updatedTextElement, + fontSize: Math.round(updatedTextElement.fontSize), + }); + } + // Make sure text editor height doesn't go beyond viewport const editorMaxHeight = (appState.height - viewportY) / appState.zoom.value; Object.assign(editable.style, { font: getFontString(updatedTextElement), // must be defined *after* font ¯\_(ツ)_/¯ - lineHeight: element.lineHeight, + lineHeight, width: `${textElementWidth}px`, height: `${textElementHeight}px`, left: `${viewportX}px`, diff --git a/src/element/types.ts b/src/element/types.ts index 4b4bad74e..0760d054d 100644 --- a/src/element/types.ts +++ b/src/element/types.ts @@ -131,6 +131,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase & fontSize: number; fontFamily: FontFamilyValues; text: string; + baseline: number; textAlign: TextAlign; verticalAlign: VerticalAlign; containerId: ExcalidrawGenericElement["id"] | null; diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index 7adcc5840..486e52bdf 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -245,7 +245,6 @@ const drawImagePlaceholder = ( size, ); }; - const drawElementOnCanvas = ( element: NonDeletedExcalidrawElement, rc: RoughCanvas, @@ -331,18 +330,16 @@ const drawElementOnCanvas = ( : element.textAlign === "right" ? element.width : 0; - context.textBaseline = "bottom"; - const lineHeightPx = getLineHeightInPx( element.fontSize, element.lineHeight, ); - + const verticalOffset = element.height - element.baseline; for (let index = 0; index < lines.length; index++) { context.fillText( lines[index], horizontalOffset, - (index + 1) * lineHeightPx, + (index + 1) * lineHeightPx - verticalOffset, ); } context.restore(); diff --git a/src/tests/data/__snapshots__/restore.test.ts.snap b/src/tests/data/__snapshots__/restore.test.ts.snap index e9a0da005..7e30b9d86 100644 --- a/src/tests/data/__snapshots__/restore.test.ts.snap +++ b/src/tests/data/__snapshots__/restore.test.ts.snap @@ -282,6 +282,7 @@ exports[`restoreElements should restore text element correctly passing value for Object { "angle": 0, "backgroundColor": "transparent", + "baseline": 0, "boundElements": Array [], "containerId": null, "fillStyle": "hachure", @@ -321,6 +322,7 @@ exports[`restoreElements should restore text element correctly with unknown font Object { "angle": 0, "backgroundColor": "transparent", + "baseline": 0, "boundElements": Array [], "containerId": null, "fillStyle": "hachure", From e4d8ba226f15836b4572fc3bae6a623e809cf08c Mon Sep 17 00:00:00 2001 From: David Luzar Date: Mon, 10 Apr 2023 15:38:50 +0200 Subject: [PATCH 015/451] feat: zigzag fill easter egg (#6439) --- src/actions/actionProperties.tsx | 92 ++++++++++++++++++----------- src/components/ButtonIconSelect.tsx | 78 ++++++++++++++++-------- src/components/icons.tsx | 7 +++ src/css/styles.scss | 3 + src/element/types.ts | 2 +- 5 files changed, 120 insertions(+), 62 deletions(-) diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index 08420d9ef..ed714816b 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -1,4 +1,5 @@ import { AppState } from "../../src/types"; +import { trackEvent } from "../analytics"; import { ButtonIconSelect } from "../components/ButtonIconSelect"; import { ColorPicker } from "../components/ColorPicker"; import { IconPicker } from "../components/IconPicker"; @@ -37,6 +38,7 @@ import { TextAlignLeftIcon, TextAlignCenterIcon, TextAlignRightIcon, + FillZigZagIcon, } from "../components/icons"; import { DEFAULT_FONT_FAMILY, @@ -294,7 +296,12 @@ export const actionChangeBackgroundColor = register({ export const actionChangeFillStyle = register({ name: "changeFillStyle", trackEvent: false, - perform: (elements, appState, value) => { + perform: (elements, appState, value, app) => { + trackEvent( + "element", + "changeFillStyle", + `${value} (${app.device.isMobile ? "mobile" : "desktop"})`, + ); return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -305,40 +312,55 @@ export const actionChangeFillStyle = register({ commitToHistory: true, }; }, - PanelComponent: ({ elements, appState, updateData }) => ( -
- {t("labels.fill")} - element.fillStyle, - appState.currentItemFillStyle, - )} - onChange={(value) => { - updateData(value); - }} - /> -
- ), + PanelComponent: ({ elements, appState, updateData }) => { + const selectedElements = getSelectedElements(elements, appState); + const allElementsZigZag = selectedElements.every( + (el) => el.fillStyle === "zigzag", + ); + + return ( +
+ {t("labels.fill")} + element.fillStyle, + appState.currentItemFillStyle, + )} + onClick={(value, event) => { + const nextValue = + event.altKey && + value === "hachure" && + selectedElements.every((el) => el.fillStyle === "hachure") + ? "zigzag" + : value; + + updateData(nextValue); + }} + /> +
+ ); + }, }); export const actionChangeStrokeWidth = register({ diff --git a/src/components/ButtonIconSelect.tsx b/src/components/ButtonIconSelect.tsx index 899ec150d..eec8870a9 100644 --- a/src/components/ButtonIconSelect.tsx +++ b/src/components/ButtonIconSelect.tsx @@ -1,33 +1,59 @@ import clsx from "clsx"; // TODO: It might be "clever" to add option.icon to the existing component -export const ButtonIconSelect = ({ - options, - value, - onChange, - group, -}: { - options: { value: T; text: string; icon: JSX.Element; testId?: string }[]; - value: T | null; - onChange: (value: T) => void; - group: string; -}) => ( +export const ButtonIconSelect = ( + props: { + options: { + value: T; + text: string; + icon: JSX.Element; + testId?: string; + /** if not supplied, defaults to value identity check */ + active?: boolean; + }[]; + value: T | null; + type?: "radio" | "button"; + } & ( + | { type?: "radio"; group: string; onChange: (value: T) => void } + | { + type: "button"; + onClick: ( + value: T, + event: React.MouseEvent, + ) => void; + } + ), +) => (
- {options.map((option) => ( -
); diff --git a/src/components/icons.tsx b/src/components/icons.tsx index 046ee490b..784e81024 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -1008,6 +1008,13 @@ export const UngroupIcon = React.memo(({ theme }: { theme: Theme }) => ), ); +export const FillZigZagIcon = createIcon( + + + , + modifiedTablerIconProps, +); + export const FillHachureIcon = createIcon( <> Date: Wed, 12 Apr 2023 02:53:36 +0530 Subject: [PATCH 016/451] fix: fixing popover overflow on small screen (#6433) Co-authored-by: dwelle --- src/components/Popover.scss | 1 + src/components/Popover.tsx | 86 ++++++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/src/components/Popover.scss b/src/components/Popover.scss index 84d16e47f..9458b5026 100644 --- a/src/components/Popover.scss +++ b/src/components/Popover.scss @@ -3,5 +3,6 @@ position: absolute; z-index: 10; padding: 5px 0 5px; + outline: none; } } diff --git a/src/components/Popover.tsx b/src/components/Popover.tsx index 9a046599b..c1249f798 100644 --- a/src/components/Popover.tsx +++ b/src/components/Popover.tsx @@ -29,13 +29,15 @@ export const Popover = ({ }: Props) => { const popoverRef = useRef(null); - const container = popoverRef.current; - useEffect(() => { + const container = popoverRef.current; + if (!container) { return; } + container.focus(); + const handleKeyDown = (event: KeyboardEvent) => { if (event.key === KEYS.TAB) { const focusableElements = queryFocusableElements(container); @@ -44,15 +46,23 @@ export const Popover = ({ (element) => element === activeElement, ); - if (currentIndex === 0 && event.shiftKey) { - focusableElements[focusableElements.length - 1].focus(); + if (activeElement === container) { + if (event.shiftKey) { + focusableElements[focusableElements.length - 1]?.focus(); + } else { + focusableElements[0].focus(); + } + event.preventDefault(); + event.stopImmediatePropagation(); + } else if (currentIndex === 0 && event.shiftKey) { + focusableElements[focusableElements.length - 1]?.focus(); event.preventDefault(); event.stopImmediatePropagation(); } else if ( currentIndex === focusableElements.length - 1 && !event.shiftKey ) { - focusableElements[0].focus(); + focusableElements[0]?.focus(); event.preventDefault(); event.stopImmediatePropagation(); } @@ -62,35 +72,59 @@ export const Popover = ({ container.addEventListener("keydown", handleKeyDown); return () => container.removeEventListener("keydown", handleKeyDown); - }, [container]); + }, []); + + const lastInitializedPosRef = useRef<{ top: number; left: number } | null>( + null, + ); // ensure the popover doesn't overflow the viewport useLayoutEffect(() => { - if (fitInViewport && popoverRef.current) { - const element = popoverRef.current; - const { x, y, width, height } = element.getBoundingClientRect(); + if (fitInViewport && popoverRef.current && top != null && left != null) { + const container = popoverRef.current; + const { width, height } = container.getBoundingClientRect(); - //Position correctly when clicked on rightmost part or the bottom part of viewport - if (x + width - offsetLeft > viewportWidth) { - element.style.left = `${viewportWidth - width - 10}px`; - } - if (y + height - offsetTop > viewportHeight) { - element.style.top = `${viewportHeight - height}px`; + // hack for StrictMode so this effect only runs once for + // the same top/left position, otherwise + // we'd potentically reposition twice (once for viewport overflow) + // and once for top/left position afterwards + if ( + lastInitializedPosRef.current?.top === top && + lastInitializedPosRef.current?.left === left + ) { + return; } + lastInitializedPosRef.current = { top, left }; - //Resize to fit viewport on smaller screens - if (height >= viewportHeight) { - element.style.height = `${viewportHeight - 20}px`; - element.style.top = "10px"; - element.style.overflowY = "scroll"; - } if (width >= viewportWidth) { - element.style.width = `${viewportWidth}px`; - element.style.left = "0px"; - element.style.overflowX = "scroll"; + container.style.width = `${viewportWidth}px`; + container.style.left = "0px"; + container.style.overflowX = "scroll"; + } else if (left + width - offsetLeft > viewportWidth) { + container.style.left = `${viewportWidth - width - 10}px`; + } else { + container.style.left = `${left}px`; + } + + if (height >= viewportHeight) { + container.style.height = `${viewportHeight - 20}px`; + container.style.top = "10px"; + container.style.overflowY = "scroll"; + } else if (top + height - offsetTop > viewportHeight) { + container.style.top = `${viewportHeight - height}px`; + } else { + container.style.top = `${top}px`; } } - }, [fitInViewport, viewportWidth, viewportHeight, offsetLeft, offsetTop]); + }, [ + top, + left, + fitInViewport, + viewportWidth, + viewportHeight, + offsetLeft, + offsetTop, + ]); useEffect(() => { if (onCloseRequest) { @@ -105,7 +139,7 @@ export const Popover = ({ }, [onCloseRequest]); return ( -
+
{children}
); From 372743f59f03b2f368ea0bf704cb37c3dca60cc5 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Wed, 12 Apr 2023 10:57:00 +0200 Subject: [PATCH 017/451] fix: autoredirect to plus in prod only (#6446) --- public/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/index.html b/public/index.html index 47a59624b..a8633fc4d 100644 --- a/public/index.html +++ b/public/index.html @@ -79,6 +79,7 @@ + <% if (process.env.NODE_ENV === "production") { %> + <% } %> From 13b27afe0f39cc43d80fa05232e985530d0f0600 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Thu, 13 Apr 2023 11:45:58 +0530 Subject: [PATCH 018/451] fix: update coords when text unbinded from its container (#6445) * fix: update coords when text unbinded from its container * Add specs --- src/actions/actionBoundText.tsx | 6 ++- src/element/textElement.ts | 8 +++- src/element/textWysiwyg.test.tsx | 39 +++++++++++++++++ src/tests/linearElementEditor.test.tsx | 59 +++++++++++++++++++++++++- 4 files changed, 109 insertions(+), 3 deletions(-) diff --git a/src/actions/actionBoundText.tsx b/src/actions/actionBoundText.tsx index 9f9fbfc0f..990f98d41 100644 --- a/src/actions/actionBoundText.tsx +++ b/src/actions/actionBoundText.tsx @@ -2,6 +2,7 @@ import { BOUND_TEXT_PADDING, ROUNDNESS, VERTICAL_ALIGN } from "../constants"; import { getNonDeletedElements, isTextElement, newElement } from "../element"; import { mutateElement } from "../element/mutateElement"; import { + computeBoundTextPosition, computeContainerDimensionForBoundText, getBoundTextElement, measureText, @@ -33,6 +34,7 @@ export const actionUnbindText = register({ trackEvent: { category: "element" }, predicate: (elements, appState) => { const selectedElements = getSelectedElements(elements, appState); + return selectedElements.some((element) => hasBoundTextElement(element)); }, perform: (elements, appState) => { @@ -52,13 +54,15 @@ export const actionUnbindText = register({ element.id, ); resetOriginalContainerCache(element.id); - + const { x, y } = computeBoundTextPosition(element, boundTextElement); mutateElement(boundTextElement as ExcalidrawTextElement, { containerId: null, width, height, baseline, text: boundTextElement.originalText, + x, + y, }); mutateElement(element, { boundElements: element.boundElements?.filter( diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 26cf91a89..38da5df5a 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -245,10 +245,16 @@ export const handleBindTextResize = ( } }; -const computeBoundTextPosition = ( +export const computeBoundTextPosition = ( container: ExcalidrawElement, boundTextElement: ExcalidrawTextElementWithContainer, ) => { + if (isArrowElement(container)) { + return LinearElementEditor.getBoundTextElementPosition( + container, + boundTextElement, + ); + } const containerCoords = getContainerCoords(container); const maxContainerHeight = getMaxContainerHeight(container); const maxContainerWidth = getMaxContainerWidth(container); diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx index cb852cd1c..c55a9befa 100644 --- a/src/element/textWysiwyg.test.tsx +++ b/src/element/textWysiwyg.test.tsx @@ -740,6 +740,45 @@ describe("textWysiwyg", () => { expect(rectangle.boundElements).toBe(null); }); + it("should bind text to container when triggered via context menu", async () => { + expect(h.elements.length).toBe(1); + expect(h.elements[0].id).toBe(rectangle.id); + + UI.clickTool("text"); + mouse.clickAt(20, 30); + const editor = document.querySelector( + ".excalidraw-textEditorContainer > textarea", + ) as HTMLTextAreaElement; + + fireEvent.change(editor, { + target: { + value: "Excalidraw is an opensource virtual collaborative whiteboard", + }, + }); + + editor.dispatchEvent(new Event("input")); + await new Promise((cb) => setTimeout(cb, 0)); + expect(h.elements.length).toBe(2); + expect(h.elements[1].type).toBe("text"); + + API.setSelectedElements([h.elements[0], h.elements[1]]); + fireEvent.contextMenu(GlobalTestState.canvas, { + button: 2, + clientX: 20, + clientY: 30, + }); + const contextMenu = document.querySelector(".context-menu"); + fireEvent.click( + queryByText(contextMenu as HTMLElement, "Bind text to the container")!, + ); + const text = h.elements[1] as ExcalidrawTextElementWithContainer; + expect(rectangle.boundElements).toStrictEqual([ + { id: h.elements[1].id, type: "text" }, + ]); + expect(text.containerId).toBe(rectangle.id); + expect(text.verticalAlign).toBe(VERTICAL_ALIGN.MIDDLE); + }); + it("should update font family correctly on undo/redo by selecting bounded text when font family was updated", async () => { expect(h.elements.length).toBe(1); diff --git a/src/tests/linearElementEditor.test.tsx b/src/tests/linearElementEditor.test.tsx index ac4d801bc..15fd105ec 100644 --- a/src/tests/linearElementEditor.test.tsx +++ b/src/tests/linearElementEditor.test.tsx @@ -23,7 +23,7 @@ import { getMaxContainerWidth, } from "../element/textElement"; import * as textElementUtils from "../element/textElement"; -import { ROUNDNESS } from "../constants"; +import { ROUNDNESS, VERTICAL_ALIGN } from "../constants"; const renderScene = jest.spyOn(Renderer, "renderScene"); @@ -1191,5 +1191,62 @@ describe("Test Linear Elements", () => { expect(queryByTestId(container, "align-horizontal-center")).toBeNull(); expect(queryByTestId(container, "align-right")).toBeNull(); }); + + it("should update label coords when a label binded via context menu is unbinded", async () => { + createTwoPointerLinearElement("arrow"); + const text = API.createElement({ + type: "text", + text: "Hello Excalidraw", + }); + expect(text.x).toBe(0); + expect(text.y).toBe(0); + + h.elements = [h.elements[0], text]; + + const container = h.elements[0]; + API.setSelectedElements([container, text]); + fireEvent.contextMenu(GlobalTestState.canvas, { + button: 2, + clientX: 20, + clientY: 30, + }); + let contextMenu = document.querySelector(".context-menu"); + + fireEvent.click( + queryByText(contextMenu as HTMLElement, "Bind text to the container")!, + ); + expect(container.boundElements).toStrictEqual([ + { id: h.elements[1].id, type: "text" }, + ]); + expect(text.containerId).toBe(container.id); + expect(text.verticalAlign).toBe(VERTICAL_ALIGN.MIDDLE); + + mouse.reset(); + mouse.clickAt( + container.x + container.width / 2, + container.y + container.height / 2, + ); + mouse.down(); + mouse.up(); + API.setSelectedElements([h.elements[0], h.elements[1]]); + + fireEvent.contextMenu(GlobalTestState.canvas, { + button: 2, + clientX: 20, + clientY: 30, + }); + contextMenu = document.querySelector(".context-menu"); + fireEvent.click(queryByText(contextMenu as HTMLElement, "Unbind text")!); + expect(container.boundElements).toEqual([]); + expect(text).toEqual( + expect.objectContaining({ + containerId: null, + width: 160, + height: 25, + x: -40, + y: 7.5, + }), + ); + }); }); }); From ca3be2c678dfc5fae50d005fdcfe3b8c84fc2544 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Thu, 13 Apr 2023 17:19:46 +0530 Subject: [PATCH 019/451] fix: exporting labelled arrows via export utils (#6443) * fix: exporting labelled arrows via export utils * add comments * lint * update changelog * fix lint * initialize scene in the utils so it can be availabe in the helper functions * fix library rendering * add comments --- src/components/LibraryUnit.tsx | 10 +++--- src/packages/excalidraw/CHANGELOG.md | 4 +++ src/packages/utils.ts | 48 ++++++++++++++++++++++++---- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/components/LibraryUnit.tsx b/src/components/LibraryUnit.tsx index 6723ac800..749877cdd 100644 --- a/src/components/LibraryUnit.tsx +++ b/src/components/LibraryUnit.tsx @@ -2,7 +2,7 @@ import clsx from "clsx"; import oc from "open-color"; import { useEffect, useRef, useState } from "react"; import { useDevice } from "../components/App"; -import { exportToSvg } from "../scene/export"; +import { exportToSvg } from "../packages/utils"; import { LibraryItem } from "../types"; import "./LibraryUnit.scss"; import { CheckboxItem } from "./CheckboxItem"; @@ -36,14 +36,14 @@ export const LibraryUnit = ({ if (!elements) { return; } - const svg = await exportToSvg( + const svg = await exportToSvg({ elements, - { + appState: { exportBackground: false, viewBackgroundColor: oc.white, }, - null, - ); + files: null, + }); svg.querySelector(".style-fonts")?.remove(); node.innerHTML = svg.outerHTML; })(); diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index 628177a4a..c36883b8e 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -33,6 +33,10 @@ For more details refer to the [docs](https://docs.excalidraw.com) - The optional parameter `refreshDimensions` in [`restoreElements`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/utils/restore#restoreelements) has been removed and can be enabled via `opts` +### Fixes + +- Exporting labelled arrows via export utils [#6443](https://github.com/excalidraw/excalidraw/pull/6443) + ## 0.14.2 (2023-02-01) ### Features diff --git a/src/packages/utils.ts b/src/packages/utils.ts index d81995080..5161e0cab 100644 --- a/src/packages/utils.ts +++ b/src/packages/utils.ts @@ -5,7 +5,6 @@ import { import { getDefaultAppState } from "../appState"; import { AppState, BinaryFiles } from "../types"; import { ExcalidrawElement, NonDeleted } from "../element/types"; -import { getNonDeletedElements } from "../element"; import { restore } from "../data/restore"; import { MIME_TYPES } from "../constants"; import { encodePngMetadata } from "../data/image"; @@ -15,6 +14,7 @@ import { copyTextToSystemClipboard, copyToClipboard, } from "../clipboard"; +import Scene from "../scene/Scene"; export { MIME_TYPES }; @@ -44,9 +44,17 @@ export const exportToCanvas = ({ null, null, ); + // The helper methods getContainerElement and getBoundTextElement are + // dependent on Scene which will not be available + // when these pure utils are called outside Excalidraw or even if called + // from inside Excalidraw when Scene isn't available eg when using library items from store, as a result the element cannot be extracted + // hence initailizing a new scene with the elements + // so its always available to helper methods + const scene = new Scene(); + scene.replaceAllElements(restoredElements); const { exportBackground, viewBackgroundColor } = restoredAppState; return _exportToCanvas( - getNonDeletedElements(restoredElements), + scene.getNonDeletedElements(), { ...restoredAppState, offsetTop: 0, offsetLeft: 0, width: 0, height: 0 }, files || {}, { exportBackground, exportPadding, viewBackgroundColor }, @@ -114,8 +122,18 @@ export const exportToBlob = async ( }; } - const canvas = await exportToCanvas(opts); - + // The helper methods getContainerElement and getBoundTextElement are + // dependent on Scene which will not be available + // when these pure utils are called outside Excalidraw or even if called + // from inside Excalidraw when Scene isn't available eg when using library items from store, as a result the element cannot be extracted + // hence initailizing a new scene with the elements + // so its always available to helper methods + const scene = new Scene(); + scene.replaceAllElements(opts.elements); + const canvas = await exportToCanvas({ + ...opts, + elements: scene.getNonDeletedElements(), + }); quality = quality ? quality : /image\/jpe?g/.test(mimeType) ? 0.92 : 0.8; return new Promise((resolve, reject) => { @@ -132,7 +150,7 @@ export const exportToBlob = async ( blob = await encodePngMetadata({ blob, metadata: serializeAsJSON( - opts.elements, + scene.getNonDeletedElements(), opts.appState, opts.files || {}, "local", @@ -160,8 +178,16 @@ export const exportToSvg = async ({ null, null, ); + // The helper methods getContainerElement and getBoundTextElement are + // dependent on Scene which will not be available + // when these pure utils are called outside Excalidraw or even if called + // from inside Excalidraw when Scene isn't available eg when using library items from store, as a result the element cannot be extracted + // hence initailizing a new scene with the elements + // so its always available to helper methods + const scene = new Scene(); + scene.replaceAllElements(restoredElements); return _exportToSvg( - getNonDeletedElements(restoredElements), + scene.getNonDeletedElements(), { ...restoredAppState, exportPadding, @@ -177,6 +203,14 @@ export const exportToClipboard = async ( type: "png" | "svg" | "json"; }, ) => { + // The helper methods getContainerElement and getBoundTextElement are + // dependent on Scene which will not be available + // when these pure utils are called outside Excalidraw or even if called + // from inside Excalidraw when Scene isn't available eg when using library items from store, as a result the element cannot be extracted + // hence initailizing a new scene with the elements + // so its always available to helper methods + const scene = new Scene(); + scene.replaceAllElements(opts.elements); if (opts.type === "svg") { const svg = await exportToSvg(opts); await copyTextToSystemClipboard(svg.outerHTML); @@ -191,7 +225,7 @@ export const exportToClipboard = async ( ...getDefaultAppState(), ...opts.appState, }; - await copyToClipboard(opts.elements, appState, opts.files); + await copyToClipboard(scene.getNonDeletedElements(), appState, opts.files); } else { throw new Error("Invalid export type"); } From 6164b5273c39de875e136aa808f1e8a7ad62ec92 Mon Sep 17 00:00:00 2001 From: Bear <68773271+SnorfYang@users.noreply.github.com> Date: Fri, 14 Apr 2023 21:22:39 +0800 Subject: [PATCH 020/451] fix: center align text when bind to container via context menu (#6451) --- src/actions/actionBoundText.tsx | 8 +++++++- src/element/textWysiwyg.test.tsx | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/actions/actionBoundText.tsx b/src/actions/actionBoundText.tsx index 990f98d41..3f240b5d8 100644 --- a/src/actions/actionBoundText.tsx +++ b/src/actions/actionBoundText.tsx @@ -1,4 +1,9 @@ -import { BOUND_TEXT_PADDING, ROUNDNESS, VERTICAL_ALIGN } from "../constants"; +import { + BOUND_TEXT_PADDING, + ROUNDNESS, + VERTICAL_ALIGN, + TEXT_ALIGN, +} from "../constants"; import { getNonDeletedElements, isTextElement, newElement } from "../element"; import { mutateElement } from "../element/mutateElement"; import { @@ -132,6 +137,7 @@ export const actionBindText = register({ mutateElement(textElement, { containerId: container.id, verticalAlign: VERTICAL_ALIGN.MIDDLE, + textAlign: TEXT_ALIGN.CENTER, }); mutateElement(container, { boundElements: (container.boundElements || []).concat({ diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx index c55a9befa..4ae3f26f9 100644 --- a/src/element/textWysiwyg.test.tsx +++ b/src/element/textWysiwyg.test.tsx @@ -777,6 +777,13 @@ describe("textWysiwyg", () => { ]); expect(text.containerId).toBe(rectangle.id); expect(text.verticalAlign).toBe(VERTICAL_ALIGN.MIDDLE); + expect(text.textAlign).toBe(TEXT_ALIGN.CENTER); + expect(text.x).toBe( + h.elements[0].x + h.elements[0].width / 2 - text.width / 2, + ); + expect(text.y).toBe( + h.elements[0].y + h.elements[0].height / 2 - text.height / 2, + ); }); it("should update font family correctly on undo/redo by selecting bounded text when font family was updated", async () => { From b0b23353cfbb2def4bcceabdfbd2f0f3cf6d7f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lie?= <110197391+fouqueta@users.noreply.github.com> Date: Fri, 14 Apr 2023 23:34:26 +0200 Subject: [PATCH 021/451] fix: split "Edit selected shape" shortcut (#6457) Co-authored-by: David Luzar --- src/components/HelpDialog.tsx | 11 ++++++----- src/locales/en.json | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/HelpDialog.tsx b/src/components/HelpDialog.tsx index 8cb775fc5..bd2f38417 100644 --- a/src/components/HelpDialog.tsx +++ b/src/components/HelpDialog.tsx @@ -165,11 +165,12 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => { shortcuts={[KEYS.E, KEYS["0"]]} /> + Date: Sun, 16 Apr 2023 11:56:25 +0200 Subject: [PATCH 022/451] fix: utils leaking Scene state (#6461 * fix: utils leaking Scene state * remove debug * doc * add tests for group duplicating * tweaks --- src/element/newElement.test.ts | 403 ++++++++++++++++++---- src/element/newElement.ts | 162 ++++++++- src/packages/utils.ts | 81 +++-- src/scene/export.ts | 7 +- src/tests/packages/utils.unmocked.test.ts | 67 ++++ 5 files changed, 604 insertions(+), 116 deletions(-) create mode 100644 src/tests/packages/utils.unmocked.test.ts diff --git a/src/element/newElement.test.ts b/src/element/newElement.test.ts index 991c034e0..ba7c63ee2 100644 --- a/src/element/newElement.test.ts +++ b/src/element/newElement.test.ts @@ -1,8 +1,9 @@ -import { duplicateElement } from "./newElement"; +import { duplicateElement, duplicateElements } from "./newElement"; import { mutateElement } from "./mutateElement"; import { API } from "../tests/helpers/api"; import { FONT_FAMILY, ROUNDNESS } from "../constants"; import { isPrimitive } from "../utils"; +import { ExcalidrawLinearElement } from "./types"; const assertCloneObjects = (source: any, clone: any) => { for (const key in clone) { @@ -15,79 +16,353 @@ const assertCloneObjects = (source: any, clone: any) => { } }; -it("clones arrow element", () => { - const element = API.createElement({ - type: "arrow", - x: 0, - y: 0, - strokeColor: "#000000", - backgroundColor: "transparent", - fillStyle: "hachure", - strokeWidth: 1, - strokeStyle: "solid", - roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS }, - roughness: 1, - opacity: 100, +describe("duplicating single elements", () => { + it("clones arrow element", () => { + const element = API.createElement({ + type: "arrow", + x: 0, + y: 0, + strokeColor: "#000000", + backgroundColor: "transparent", + fillStyle: "hachure", + strokeWidth: 1, + strokeStyle: "solid", + roundness: { type: ROUNDNESS.PROPORTIONAL_RADIUS }, + roughness: 1, + opacity: 100, + }); + + // @ts-ignore + element.__proto__ = { hello: "world" }; + + mutateElement(element, { + points: [ + [1, 2], + [3, 4], + ], + }); + + const copy = duplicateElement(null, new Map(), element); + + assertCloneObjects(element, copy); + + // assert we clone the object's prototype + // @ts-ignore + expect(copy.__proto__).toEqual({ hello: "world" }); + expect(copy.hasOwnProperty("hello")).toBe(false); + + expect(copy.points).not.toBe(element.points); + expect(copy).not.toHaveProperty("shape"); + expect(copy.id).not.toBe(element.id); + expect(typeof copy.id).toBe("string"); + expect(copy.seed).not.toBe(element.seed); + expect(typeof copy.seed).toBe("number"); + expect(copy).toEqual({ + ...element, + id: copy.id, + seed: copy.seed, + }); }); - // @ts-ignore - element.__proto__ = { hello: "world" }; + it("clones text element", () => { + const element = API.createElement({ + type: "text", + x: 0, + y: 0, + strokeColor: "#000000", + backgroundColor: "transparent", + fillStyle: "hachure", + strokeWidth: 1, + strokeStyle: "solid", + roundness: null, + roughness: 1, + opacity: 100, + text: "hello", + fontSize: 20, + fontFamily: FONT_FAMILY.Virgil, + textAlign: "left", + verticalAlign: "top", + }); - mutateElement(element, { - points: [ - [1, 2], - [3, 4], - ], - }); + const copy = duplicateElement(null, new Map(), element); - const copy = duplicateElement(null, new Map(), element); + assertCloneObjects(element, copy); - assertCloneObjects(element, copy); - - // @ts-ignore - expect(copy.__proto__).toEqual({ hello: "world" }); - expect(copy.hasOwnProperty("hello")).toBe(false); - - expect(copy.points).not.toBe(element.points); - expect(copy).not.toHaveProperty("shape"); - expect(copy.id).not.toBe(element.id); - expect(typeof copy.id).toBe("string"); - expect(copy.seed).not.toBe(element.seed); - expect(typeof copy.seed).toBe("number"); - expect(copy).toEqual({ - ...element, - id: copy.id, - seed: copy.seed, + expect(copy).not.toHaveProperty("points"); + expect(copy).not.toHaveProperty("shape"); + expect(copy.id).not.toBe(element.id); + expect(typeof copy.id).toBe("string"); + expect(typeof copy.seed).toBe("number"); }); }); -it("clones text element", () => { - const element = API.createElement({ - type: "text", - x: 0, - y: 0, - strokeColor: "#000000", - backgroundColor: "transparent", - fillStyle: "hachure", - strokeWidth: 1, - strokeStyle: "solid", - roundness: null, - roughness: 1, - opacity: 100, - text: "hello", - fontSize: 20, - fontFamily: FONT_FAMILY.Virgil, - textAlign: "left", - verticalAlign: "top", +describe("duplicating multiple elements", () => { + it("duplicateElements should clone bindings", () => { + const rectangle1 = API.createElement({ + type: "rectangle", + id: "rectangle1", + boundElements: [ + { id: "arrow1", type: "arrow" }, + { id: "arrow2", type: "arrow" }, + { id: "text1", type: "text" }, + ], + }); + + const text1 = API.createElement({ + type: "text", + id: "text1", + containerId: "rectangle1", + }); + + const arrow1 = API.createElement({ + type: "arrow", + id: "arrow1", + startBinding: { + elementId: "rectangle1", + focus: 0.2, + gap: 7, + }, + }); + + const arrow2 = API.createElement({ + type: "arrow", + id: "arrow2", + endBinding: { + elementId: "rectangle1", + focus: 0.2, + gap: 7, + }, + boundElements: [{ id: "text2", type: "text" }], + }); + + const text2 = API.createElement({ + type: "text", + id: "text2", + containerId: "arrow2", + }); + + // ------------------------------------------------------------------------- + + const origElements = [rectangle1, text1, arrow1, arrow2, text2] as const; + const clonedElements = duplicateElements(origElements); + + // generic id in-equality checks + // -------------------------------------------------------------------------- + expect(origElements.map((e) => e.type)).toEqual( + clonedElements.map((e) => e.type), + ); + origElements.forEach((origElement, idx) => { + const clonedElement = clonedElements[idx]; + expect(origElement).toEqual( + expect.objectContaining({ + id: expect.not.stringMatching(clonedElement.id), + type: clonedElement.type, + }), + ); + if ("containerId" in origElement) { + expect(origElement.containerId).not.toBe( + (clonedElement as any).containerId, + ); + } + if ("endBinding" in origElement) { + if (origElement.endBinding) { + expect(origElement.endBinding.elementId).not.toBe( + (clonedElement as any).endBinding?.elementId, + ); + } else { + expect((clonedElement as any).endBinding).toBeNull(); + } + } + if ("startBinding" in origElement) { + if (origElement.startBinding) { + expect(origElement.startBinding.elementId).not.toBe( + (clonedElement as any).startBinding?.elementId, + ); + } else { + expect((clonedElement as any).startBinding).toBeNull(); + } + } + }); + // -------------------------------------------------------------------------- + + const clonedArrows = clonedElements.filter( + (e) => e.type === "arrow", + ) as ExcalidrawLinearElement[]; + + const [clonedRectangle, clonedText1, , clonedArrow2, clonedArrowLabel] = + clonedElements as any as typeof origElements; + + expect(clonedText1.containerId).toBe(clonedRectangle.id); + expect( + clonedRectangle.boundElements!.find((e) => e.id === clonedText1.id), + ).toEqual( + expect.objectContaining({ + id: clonedText1.id, + type: clonedText1.type, + }), + ); + + clonedArrows.forEach((arrow) => { + // console.log(arrow); + expect( + clonedRectangle.boundElements!.find((e) => e.id === arrow.id), + ).toEqual( + expect.objectContaining({ + id: arrow.id, + type: arrow.type, + }), + ); + + if (arrow.endBinding) { + expect(arrow.endBinding.elementId).toBe(clonedRectangle.id); + } + if (arrow.startBinding) { + expect(arrow.startBinding.elementId).toBe(clonedRectangle.id); + } + }); + + expect(clonedArrow2.boundElements).toEqual([ + { type: "text", id: clonedArrowLabel.id }, + ]); + expect(clonedArrowLabel.containerId).toBe(clonedArrow2.id); }); - const copy = duplicateElement(null, new Map(), element); + it("should remove id references of elements that aren't found", () => { + const rectangle1 = API.createElement({ + type: "rectangle", + id: "rectangle1", + boundElements: [ + // should keep + { id: "arrow1", type: "arrow" }, + // should drop + { id: "arrow-not-exists", type: "arrow" }, + // should drop + { id: "text-not-exists", type: "text" }, + ], + }); - assertCloneObjects(element, copy); + const arrow1 = API.createElement({ + type: "arrow", + id: "arrow1", + startBinding: { + elementId: "rectangle1", + focus: 0.2, + gap: 7, + }, + }); - expect(copy).not.toHaveProperty("points"); - expect(copy).not.toHaveProperty("shape"); - expect(copy.id).not.toBe(element.id); - expect(typeof copy.id).toBe("string"); - expect(typeof copy.seed).toBe("number"); + const text1 = API.createElement({ + type: "text", + id: "text1", + containerId: "rectangle-not-exists", + }); + + const arrow2 = API.createElement({ + type: "arrow", + id: "arrow2", + startBinding: { + elementId: "rectangle1", + focus: 0.2, + gap: 7, + }, + endBinding: { + elementId: "rectangle-not-exists", + focus: 0.2, + gap: 7, + }, + }); + + const arrow3 = API.createElement({ + type: "arrow", + id: "arrow2", + startBinding: { + elementId: "rectangle-not-exists", + focus: 0.2, + gap: 7, + }, + endBinding: { + elementId: "rectangle1", + focus: 0.2, + gap: 7, + }, + }); + + // ------------------------------------------------------------------------- + + const origElements = [rectangle1, text1, arrow1, arrow2, arrow3] as const; + const clonedElements = duplicateElements( + origElements, + ) as any as typeof origElements; + const [ + clonedRectangle, + clonedText1, + clonedArrow1, + clonedArrow2, + clonedArrow3, + ] = clonedElements; + + expect(clonedRectangle.boundElements).toEqual([ + { id: clonedArrow1.id, type: "arrow" }, + ]); + + expect(clonedText1.containerId).toBe(null); + + expect(clonedArrow2.startBinding).toEqual({ + ...arrow2.startBinding, + elementId: clonedRectangle.id, + }); + expect(clonedArrow2.endBinding).toBe(null); + + expect(clonedArrow3.startBinding).toBe(null); + expect(clonedArrow3.endBinding).toEqual({ + ...arrow3.endBinding, + elementId: clonedRectangle.id, + }); + }); + + describe("should duplicate all group ids", () => { + it("should regenerate all group ids and keep them consistent across elements", () => { + const rectangle1 = API.createElement({ + type: "rectangle", + groupIds: ["g1"], + }); + const rectangle2 = API.createElement({ + type: "rectangle", + groupIds: ["g2", "g1"], + }); + const rectangle3 = API.createElement({ + type: "rectangle", + groupIds: ["g2", "g1"], + }); + + const origElements = [rectangle1, rectangle2, rectangle3] as const; + const clonedElements = duplicateElements( + origElements, + ) as any as typeof origElements; + const [clonedRectangle1, clonedRectangle2, clonedRectangle3] = + clonedElements; + + expect(rectangle1.groupIds[0]).not.toBe(clonedRectangle1.groupIds[0]); + expect(rectangle2.groupIds[0]).not.toBe(clonedRectangle2.groupIds[0]); + expect(rectangle2.groupIds[1]).not.toBe(clonedRectangle2.groupIds[1]); + + expect(clonedRectangle1.groupIds[0]).toBe(clonedRectangle2.groupIds[1]); + expect(clonedRectangle2.groupIds[0]).toBe(clonedRectangle3.groupIds[0]); + expect(clonedRectangle2.groupIds[1]).toBe(clonedRectangle3.groupIds[1]); + }); + + it("should keep and regenerate ids of groups even if invalid", () => { + // lone element shouldn't be able to be grouped with itself, + // but hard to check against in a performant way so we ignore it + const rectangle1 = API.createElement({ + type: "rectangle", + groupIds: ["g1"], + }); + + const [clonedRectangle1] = duplicateElements([rectangle1]); + + expect(typeof clonedRectangle1.groupIds[0]).toBe("string"); + expect(rectangle1.groupIds[0]).not.toBe(clonedRectangle1.groupIds[0]); + }); + }); }); diff --git a/src/element/newElement.ts b/src/element/newElement.ts index b6b6cad2d..72aa54684 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -13,7 +13,12 @@ import { FontFamilyValues, ExcalidrawTextContainer, } from "../element/types"; -import { getFontString, getUpdatedTimestamp, isTestEnv } from "../utils"; +import { + arrayToMap, + getFontString, + getUpdatedTimestamp, + isTestEnv, +} from "../utils"; import { randomInteger, randomId } from "../random"; import { mutateElement, newElementWith } from "./mutateElement"; import { getNewGroupIdsForDuplication } from "../groups"; @@ -357,16 +362,24 @@ export const newImageElement = ( }; }; -// Simplified deep clone for the purpose of cloning ExcalidrawElement only -// (doesn't clone Date, RegExp, Map, Set, Typed arrays etc.) +// Simplified deep clone for the purpose of cloning ExcalidrawElement. +// +// Only clones plain objects and arrays. Doesn't clone Date, RegExp, Map, Set, +// Typed arrays and other non-null objects. // // Adapted from https://github.com/lukeed/klona -export const deepCopyElement = (val: any, depth: number = 0) => { +// +// The reason for `deepCopyElement()` wrapper is type safety (only allow +// passing ExcalidrawElement as the top-level argument). +const _deepCopyElement = (val: any, depth: number = 0) => { + // only clone non-primitives if (val == null || typeof val !== "object") { return val; } - if (Object.prototype.toString.call(val) === "[object Object]") { + const objectType = Object.prototype.toString.call(val); + + if (objectType === "[object Object]") { const tmp = typeof val.constructor === "function" ? Object.create(Object.getPrototypeOf(val)) @@ -378,7 +391,7 @@ export const deepCopyElement = (val: any, depth: number = 0) => { if (depth === 0 && (key === "shape" || key === "canvas")) { continue; } - tmp[key] = deepCopyElement(val[key], depth + 1); + tmp[key] = _deepCopyElement(val[key], depth + 1); } } return tmp; @@ -388,14 +401,44 @@ export const deepCopyElement = (val: any, depth: number = 0) => { let k = val.length; const arr = new Array(k); while (k--) { - arr[k] = deepCopyElement(val[k], depth + 1); + arr[k] = _deepCopyElement(val[k], depth + 1); } return arr; } + // we're not cloning non-array & non-plain-object objects because we + // don't support them on excalidraw elements yet. If we do, we need to make + // sure we start cloning them, so let's warn about it. + if (process.env.NODE_ENV === "development") { + if ( + objectType !== "[object Object]" && + objectType !== "[object Array]" && + objectType.startsWith("[object ") + ) { + console.warn( + `_deepCloneElement: unexpected object type ${objectType}. This value will not be cloned!`, + ); + } + } + return val; }; +/** + * Clones ExcalidrawElement data structure. Does not regenerate id, nonce, or + * any value. The purpose is to to break object references for immutability + * reasons, whenever we want to keep the original element, but ensure it's not + * mutated. + * + * Only clones plain objects and arrays. Doesn't clone Date, RegExp, Map, Set, + * Typed arrays and other non-null objects. + */ +export const deepCopyElement = ( + val: T, +): Mutable => { + return _deepCopyElement(val); +}; + /** * Duplicate an element, often used in the alt-drag operation. * Note that this method has gotten a bit complicated since the @@ -410,13 +453,13 @@ export const deepCopyElement = (val: any, depth: number = 0) => { * @param element Element to duplicate * @param overrides Any element properties to override */ -export const duplicateElement = >( +export const duplicateElement = ( editingGroupId: AppState["editingGroupId"], groupIdMapForOperation: Map, element: TElement, overrides?: Partial, -): TElement => { - let copy: TElement = deepCopyElement(element); +): Readonly => { + let copy = deepCopyElement(element); if (isTestEnv()) { copy.id = `${copy.id}_copy`; @@ -449,3 +492,102 @@ export const duplicateElement = >( } return copy; }; + +/** + * Clones elements, regenerating their ids (including bindings) and group ids. + * + * If bindings don't exist in the elements array, they are removed. Therefore, + * it's advised to supply the whole elements array, or sets of elements that + * are encapsulated (such as library items), if the purpose is to retain + * bindings to the cloned elements intact. + */ +export const duplicateElements = (elements: readonly ExcalidrawElement[]) => { + const clonedElements: ExcalidrawElement[] = []; + + const origElementsMap = arrayToMap(elements); + + // used for for migrating old ids to new ids + const elementNewIdsMap = new Map< + /* orig */ ExcalidrawElement["id"], + /* new */ ExcalidrawElement["id"] + >(); + + const maybeGetNewId = (id: ExcalidrawElement["id"]) => { + // if we've already migrated the element id, return the new one directly + if (elementNewIdsMap.has(id)) { + return elementNewIdsMap.get(id)!; + } + // if we haven't migrated the element id, but an old element with the same + // id exists, generate a new id for it and return it + if (origElementsMap.has(id)) { + const newId = randomId(); + elementNewIdsMap.set(id, newId); + return newId; + } + // if old element doesn't exist, return null to mark it for removal + return null; + }; + + const groupNewIdsMap = new Map(); + + for (const element of elements) { + const clonedElement: Mutable = _deepCopyElement(element); + + clonedElement.id = maybeGetNewId(element.id)!; + + if (clonedElement.groupIds) { + clonedElement.groupIds = clonedElement.groupIds.map((groupId) => { + if (!groupNewIdsMap.has(groupId)) { + groupNewIdsMap.set(groupId, randomId()); + } + return groupNewIdsMap.get(groupId)!; + }); + } + + if ("containerId" in clonedElement && clonedElement.containerId) { + const newContainerId = maybeGetNewId(clonedElement.containerId); + clonedElement.containerId = newContainerId; + } + + if ("boundElements" in clonedElement && clonedElement.boundElements) { + clonedElement.boundElements = clonedElement.boundElements.reduce( + ( + acc: Mutable>, + binding, + ) => { + const newBindingId = maybeGetNewId(binding.id); + if (newBindingId) { + acc.push({ ...binding, id: newBindingId }); + } + return acc; + }, + [], + ); + } + + if ("endBinding" in clonedElement && clonedElement.endBinding) { + const newEndBindingId = maybeGetNewId(clonedElement.endBinding.elementId); + clonedElement.endBinding = newEndBindingId + ? { + ...clonedElement.endBinding, + elementId: newEndBindingId, + } + : null; + } + if ("startBinding" in clonedElement && clonedElement.startBinding) { + const newEndBindingId = maybeGetNewId( + clonedElement.startBinding.elementId, + ); + clonedElement.startBinding = newEndBindingId + ? { + ...clonedElement.startBinding, + elementId: newEndBindingId, + } + : null; + } + + clonedElements.push(clonedElement); + } + + return clonedElements; +}; diff --git a/src/packages/utils.ts b/src/packages/utils.ts index 5161e0cab..1fb6cd3d9 100644 --- a/src/packages/utils.ts +++ b/src/packages/utils.ts @@ -15,6 +15,23 @@ import { copyToClipboard, } from "../clipboard"; import Scene from "../scene/Scene"; +import { duplicateElements } from "../element/newElement"; + +// getContainerElement and getBoundTextElement and potentially other helpers +// depend on `Scene` which will not be available when these pure utils are +// called outside initialized Excalidraw editor instance or even if called +// from inside Excalidraw if the elements were never cached by Scene (e.g. +// for library elements). +// +// As such, before passing the elements down, we need to initialize a custom +// Scene instance and assign them to it. +// +// FIXME This is a super hacky workaround and we'll need to rewrite this soon. +const passElementsSafely = (elements: readonly ExcalidrawElement[]) => { + const scene = new Scene(); + scene.replaceAllElements(duplicateElements(elements)); + return scene.getNonDeletedElements(); +}; export { MIME_TYPES }; @@ -44,17 +61,9 @@ export const exportToCanvas = ({ null, null, ); - // The helper methods getContainerElement and getBoundTextElement are - // dependent on Scene which will not be available - // when these pure utils are called outside Excalidraw or even if called - // from inside Excalidraw when Scene isn't available eg when using library items from store, as a result the element cannot be extracted - // hence initailizing a new scene with the elements - // so its always available to helper methods - const scene = new Scene(); - scene.replaceAllElements(restoredElements); const { exportBackground, viewBackgroundColor } = restoredAppState; return _exportToCanvas( - scene.getNonDeletedElements(), + passElementsSafely(restoredElements), { ...restoredAppState, offsetTop: 0, offsetLeft: 0, width: 0, height: 0 }, files || {}, { exportBackground, exportPadding, viewBackgroundColor }, @@ -122,17 +131,9 @@ export const exportToBlob = async ( }; } - // The helper methods getContainerElement and getBoundTextElement are - // dependent on Scene which will not be available - // when these pure utils are called outside Excalidraw or even if called - // from inside Excalidraw when Scene isn't available eg when using library items from store, as a result the element cannot be extracted - // hence initailizing a new scene with the elements - // so its always available to helper methods - const scene = new Scene(); - scene.replaceAllElements(opts.elements); const canvas = await exportToCanvas({ ...opts, - elements: scene.getNonDeletedElements(), + elements: passElementsSafely(opts.elements), }); quality = quality ? quality : /image\/jpe?g/.test(mimeType) ? 0.92 : 0.8; @@ -150,7 +151,10 @@ export const exportToBlob = async ( blob = await encodePngMetadata({ blob, metadata: serializeAsJSON( - scene.getNonDeletedElements(), + // NOTE as long as we're using the Scene hack, we need to ensure + // we pass the original, uncloned elements when serializing + // so that we keep ids stable + opts.elements, opts.appState, opts.files || {}, "local", @@ -178,21 +182,24 @@ export const exportToSvg = async ({ null, null, ); - // The helper methods getContainerElement and getBoundTextElement are - // dependent on Scene which will not be available - // when these pure utils are called outside Excalidraw or even if called - // from inside Excalidraw when Scene isn't available eg when using library items from store, as a result the element cannot be extracted - // hence initailizing a new scene with the elements - // so its always available to helper methods - const scene = new Scene(); - scene.replaceAllElements(restoredElements); + + const exportAppState = { + ...restoredAppState, + exportPadding, + }; + return _exportToSvg( - scene.getNonDeletedElements(), - { - ...restoredAppState, - exportPadding, - }, + passElementsSafely(restoredElements), + exportAppState, files, + { + // NOTE as long as we're using the Scene hack, we need to ensure + // we pass the original, uncloned elements when serializing + // so that we keep ids stable. Hence adding the serializeAsJSON helper + // support into the downstream exportToSvg function. + serializeAsJSON: () => + serializeAsJSON(restoredElements, exportAppState, files || {}, "local"), + }, ); }; @@ -203,14 +210,6 @@ export const exportToClipboard = async ( type: "png" | "svg" | "json"; }, ) => { - // The helper methods getContainerElement and getBoundTextElement are - // dependent on Scene which will not be available - // when these pure utils are called outside Excalidraw or even if called - // from inside Excalidraw when Scene isn't available eg when using library items from store, as a result the element cannot be extracted - // hence initailizing a new scene with the elements - // so its always available to helper methods - const scene = new Scene(); - scene.replaceAllElements(opts.elements); if (opts.type === "svg") { const svg = await exportToSvg(opts); await copyTextToSystemClipboard(svg.outerHTML); @@ -225,7 +224,7 @@ export const exportToClipboard = async ( ...getDefaultAppState(), ...opts.appState, }; - await copyToClipboard(scene.getNonDeletedElements(), appState, opts.files); + await copyToClipboard(opts.elements, appState, opts.files); } else { throw new Error("Invalid export type"); } diff --git a/src/scene/export.ts b/src/scene/export.ts index a6e4297ad..6c5712be6 100644 --- a/src/scene/export.ts +++ b/src/scene/export.ts @@ -90,6 +90,9 @@ export const exportToSvg = async ( exportEmbedScene?: boolean; }, files: BinaryFiles | null, + opts?: { + serializeAsJSON?: () => string; + }, ): Promise => { const { exportPadding = DEFAULT_EXPORT_PADDING, @@ -103,7 +106,9 @@ export const exportToSvg = async ( metadata = await ( await import(/* webpackChunkName: "image" */ "../../src/data/image") ).encodeSvgMetadata({ - text: serializeAsJSON(elements, appState, files || {}, "local"), + text: opts?.serializeAsJSON + ? opts?.serializeAsJSON?.() + : serializeAsJSON(elements, appState, files || {}, "local"), }); } catch (error: any) { console.error(error); diff --git a/src/tests/packages/utils.unmocked.test.ts b/src/tests/packages/utils.unmocked.test.ts new file mode 100644 index 000000000..28db08c49 --- /dev/null +++ b/src/tests/packages/utils.unmocked.test.ts @@ -0,0 +1,67 @@ +import { decodePngMetadata, decodeSvgMetadata } from "../../data/image"; +import { ImportedDataState } from "../../data/types"; +import * as utils from "../../packages/utils"; +import { API } from "../helpers/api"; + +// NOTE this test file is using the actual API, unmocked. Hence splitting it +// from the other test file, because I couldn't figure out how to test +// mocked and unmocked API in the same file. + +describe("embedding scene data", () => { + describe("exportToSvg", () => { + it("embedding scene data shouldn't modify them", async () => { + const rectangle = API.createElement({ type: "rectangle" }); + const ellipse = API.createElement({ type: "ellipse" }); + + const sourceElements = [rectangle, ellipse]; + + const svgNode = await utils.exportToSvg({ + elements: sourceElements, + appState: { + viewBackgroundColor: "#ffffff", + gridSize: null, + exportEmbedScene: true, + }, + files: null, + }); + + const svg = svgNode.outerHTML; + + const parsedString = await decodeSvgMetadata({ svg }); + const importedData: ImportedDataState = JSON.parse(parsedString); + + expect(sourceElements.map((x) => x.id)).toEqual( + importedData.elements?.map((el) => el.id), + ); + }); + }); + + // skipped because we can't test png encoding right now + // (canvas.toBlob not supported in jsdom) + describe.skip("exportToBlob", () => { + it("embedding scene data shouldn't modify them", async () => { + const rectangle = API.createElement({ type: "rectangle" }); + const ellipse = API.createElement({ type: "ellipse" }); + + const sourceElements = [rectangle, ellipse]; + + const blob = await utils.exportToBlob({ + mimeType: "image/png", + elements: sourceElements, + appState: { + viewBackgroundColor: "#ffffff", + gridSize: null, + exportEmbedScene: true, + }, + files: null, + }); + + const parsedString = await decodePngMetadata(blob); + const importedData: ImportedDataState = JSON.parse(parsedString); + + expect(sourceElements.map((x) => x.id)).toEqual( + importedData.elements?.map((el) => el.id), + ); + }); + }); +}); From e31230f78cc40ff40ef4b4add54131e7c427e655 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Sun, 16 Apr 2023 11:57:13 +0200 Subject: [PATCH 023/451] refactor: inline `SingleLibraryItem` into `PublishLibrary` (#6462 refactor: inline `SingleLibraryItem` into `PublishLibrary` to reduce api surface area --- src/components/PublishLibrary.scss | 76 +++++++++++++++++++ src/components/PublishLibrary.tsx | 104 ++++++++++++++++++++++++-- src/components/SingleLibraryItem.scss | 79 ------------------- src/components/SingleLibraryItem.tsx | 104 -------------------------- 4 files changed, 175 insertions(+), 188 deletions(-) delete mode 100644 src/components/SingleLibraryItem.scss delete mode 100644 src/components/SingleLibraryItem.tsx diff --git a/src/components/PublishLibrary.scss b/src/components/PublishLibrary.scss index 6040ff2f4..fd7db0fe4 100644 --- a/src/components/PublishLibrary.scss +++ b/src/components/PublishLibrary.scss @@ -93,4 +93,80 @@ display: block; } } + + .single-library-item { + position: relative; + + &-status { + position: absolute; + top: 0.3rem; + left: 0.3rem; + font-size: 0.7rem; + color: $oc-red-7; + background: rgba(255, 255, 255, 0.9); + padding: 0.1rem 0.2rem; + border-radius: 0.2rem; + } + + &__svg { + background-color: $oc-white; + padding: 0.3rem; + width: 7.5rem; + height: 7.5rem; + border: 1px solid var(--button-gray-2); + svg { + width: 100%; + height: 100%; + } + } + + .ToolIcon__icon { + background-color: $oc-white; + width: auto; + height: auto; + margin: 0 0.5rem; + } + .ToolIcon, + .ToolIcon_type_button:hover { + background-color: white; + } + .required, + .error { + color: $oc-red-8; + font-weight: bold; + font-size: 1rem; + margin: 0.2rem; + } + .error { + font-weight: 500; + margin: 0; + padding: 0.3em 0; + } + + &--remove { + position: absolute; + top: 0.2rem; + right: 1rem; + + .ToolIcon__icon { + margin: 0; + } + .ToolIcon__icon { + background-color: $oc-red-6; + &:hover { + background-color: $oc-red-7; + } + &:active { + background-color: $oc-red-8; + } + } + svg { + color: $oc-white; + padding: 0.26rem; + border-radius: 0.3em; + width: 1rem; + height: 1rem; + } + } + } } diff --git a/src/components/PublishLibrary.tsx b/src/components/PublishLibrary.tsx index 0d060dfaa..b4233222d 100644 --- a/src/components/PublishLibrary.tsx +++ b/src/components/PublishLibrary.tsx @@ -1,11 +1,11 @@ -import { ReactNode, useCallback, useEffect, useState } from "react"; +import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; import OpenColor from "open-color"; import { Dialog } from "./Dialog"; import { t } from "../i18n"; import { AppState, LibraryItems, LibraryItem } from "../types"; -import { exportToCanvas } from "../packages/utils"; +import { exportToCanvas, exportToSvg } from "../packages/utils"; import { EXPORT_DATA_TYPES, EXPORT_SOURCE, @@ -13,12 +13,13 @@ import { VERSIONS, } from "../constants"; import { ExportedLibraryData } from "../data/types"; - -import "./PublishLibrary.scss"; -import SingleLibraryItem from "./SingleLibraryItem"; import { canvasToBlob, resizeImageFile } from "../data/blob"; import { chunk } from "../utils"; import DialogActionButton from "./DialogActionButton"; +import { CloseIcon } from "./icons"; +import { ToolButton } from "./ToolButton"; + +import "./PublishLibrary.scss"; interface PublishLibraryDataParams { authorName: string; @@ -126,6 +127,99 @@ const generatePreviewImage = async (libraryItems: LibraryItems) => { ); }; +const SingleLibraryItem = ({ + libItem, + appState, + index, + onChange, + onRemove, +}: { + libItem: LibraryItem; + appState: AppState; + index: number; + onChange: (val: string, index: number) => void; + onRemove: (id: string) => void; +}) => { + const svgRef = useRef(null); + const inputRef = useRef(null); + + useEffect(() => { + const node = svgRef.current; + if (!node) { + return; + } + (async () => { + const svg = await exportToSvg({ + elements: libItem.elements, + appState: { + ...appState, + viewBackgroundColor: OpenColor.white, + exportBackground: true, + }, + files: null, + }); + node.innerHTML = svg.outerHTML; + })(); + }, [libItem.elements, appState]); + + return ( +
+ {libItem.status === "published" && ( + + {t("labels.statusPublished")} + + )} +
+ +
+ + {libItem.error} +
+
+ ); +}; + const PublishLibrary = ({ onClose, libraryItems, diff --git a/src/components/SingleLibraryItem.scss b/src/components/SingleLibraryItem.scss deleted file mode 100644 index 0a42992a1..000000000 --- a/src/components/SingleLibraryItem.scss +++ /dev/null @@ -1,79 +0,0 @@ -@import "../css/variables.module"; - -.excalidraw { - .single-library-item { - position: relative; - - &-status { - position: absolute; - top: 0.3rem; - left: 0.3rem; - font-size: 0.7rem; - color: $oc-red-7; - background: rgba(255, 255, 255, 0.9); - padding: 0.1rem 0.2rem; - border-radius: 0.2rem; - } - - &__svg { - background-color: $oc-white; - padding: 0.3rem; - width: 7.5rem; - height: 7.5rem; - border: 1px solid var(--button-gray-2); - svg { - width: 100%; - height: 100%; - } - } - - .ToolIcon__icon { - background-color: $oc-white; - width: auto; - height: auto; - margin: 0 0.5rem; - } - .ToolIcon, - .ToolIcon_type_button:hover { - background-color: white; - } - .required, - .error { - color: $oc-red-8; - font-weight: bold; - font-size: 1rem; - margin: 0.2rem; - } - .error { - font-weight: 500; - margin: 0; - padding: 0.3em 0; - } - - &--remove { - position: absolute; - top: 0.2rem; - right: 1rem; - - .ToolIcon__icon { - margin: 0; - } - .ToolIcon__icon { - background-color: $oc-red-6; - &:hover { - background-color: $oc-red-7; - } - &:active { - background-color: $oc-red-8; - } - } - svg { - color: $oc-white; - padding: 0.26rem; - border-radius: 0.3em; - width: 1rem; - height: 1rem; - } - } - } -} diff --git a/src/components/SingleLibraryItem.tsx b/src/components/SingleLibraryItem.tsx deleted file mode 100644 index 45959199c..000000000 --- a/src/components/SingleLibraryItem.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import oc from "open-color"; -import { useEffect, useRef } from "react"; -import { t } from "../i18n"; -import { exportToSvg } from "../packages/utils"; -import { AppState, LibraryItem } from "../types"; -import { CloseIcon } from "./icons"; - -import "./SingleLibraryItem.scss"; -import { ToolButton } from "./ToolButton"; - -const SingleLibraryItem = ({ - libItem, - appState, - index, - onChange, - onRemove, -}: { - libItem: LibraryItem; - appState: AppState; - index: number; - onChange: (val: string, index: number) => void; - onRemove: (id: string) => void; -}) => { - const svgRef = useRef(null); - const inputRef = useRef(null); - - useEffect(() => { - const node = svgRef.current; - if (!node) { - return; - } - (async () => { - const svg = await exportToSvg({ - elements: libItem.elements, - appState: { - ...appState, - viewBackgroundColor: oc.white, - exportBackground: true, - }, - files: null, - }); - node.innerHTML = svg.outerHTML; - })(); - }, [libItem.elements, appState]); - - return ( -
- {libItem.status === "published" && ( - - {t("labels.statusPublished")} - - )} -
- -
- - {libItem.error} -
-
- ); -}; - -export default SingleLibraryItem; From d34cd3072f0789870a8591cafdabc0c06c08a469 Mon Sep 17 00:00:00 2001 From: zsviczian Date: Sun, 16 Apr 2023 15:33:16 +0200 Subject: [PATCH 024/451] fix: abort freedraw line if second touch is detected (#6440) --- src/components/App.tsx | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 9b4fc864d..1ebdc7713 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -3500,6 +3500,43 @@ class App extends React.Component { this.setState({ contextMenu: null }); } + this.updateGestureOnPointerDown(event); + + // if dragging element is freedraw and another pointerdown event occurs + // a second finger is on the screen + // discard the freedraw element if it is very short because it is likely + // just a spike, otherwise finalize the freedraw element when the second + // finger is lifted + if ( + event.pointerType === "touch" && + this.state.draggingElement && + this.state.draggingElement.type === "freedraw" + ) { + const element = this.state.draggingElement as ExcalidrawFreeDrawElement; + this.updateScene({ + ...(element.points.length < 10 + ? { + elements: this.scene + .getElementsIncludingDeleted() + .filter((el) => el.id !== element.id), + } + : {}), + appState: { + draggingElement: null, + editingElement: null, + startBoundElement: null, + suggestedBindings: [], + selectedElementIds: Object.keys(this.state.selectedElementIds) + .filter((key) => key !== element.id) + .reduce((obj: { [id: string]: boolean }, key) => { + obj[key] = this.state.selectedElementIds[key]; + return obj; + }, {}), + }, + }); + return; + } + // remove any active selection when we start to interact with canvas // (mainly, we care about removing selection outside the component which // would prevent our copy handling otherwise) @@ -3539,8 +3576,6 @@ class App extends React.Component { }); this.savePointer(event.clientX, event.clientY, "down"); - this.updateGestureOnPointerDown(event); - if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) { return; } From 034113772d80910b6e5335db946499d9135e46ce Mon Sep 17 00:00:00 2001 From: David Luzar Date: Sun, 16 Apr 2023 15:33:30 +0200 Subject: [PATCH 025/451] fix: color picker keyboard handling not working (#6464) --- src/components/Popover.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/Popover.tsx b/src/components/Popover.tsx index c1249f798..987e9fb91 100644 --- a/src/components/Popover.tsx +++ b/src/components/Popover.tsx @@ -36,7 +36,13 @@ export const Popover = ({ return; } - container.focus(); + // focus popover only if the caller didn't focus on something else nested + // within the popover, which should take precedence. Fixes cases + // like color picker listening to keydown events on containers nested + // in the popover. + if (!container.contains(document.activeElement)) { + container.focus(); + } const handleKeyDown = (event: KeyboardEvent) => { if (event.key === KEYS.TAB) { From e9064a4a87f1086238bc4c3e26bca1d0937e9517 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Sun, 16 Apr 2023 17:09:51 +0200 Subject: [PATCH 026/451] fix: library ids cross-contamination on multiple insert (#6466) --- src/components/LibraryMenuItems.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/LibraryMenuItems.tsx b/src/components/LibraryMenuItems.tsx index f6189fcb7..7ae6517a8 100644 --- a/src/components/LibraryMenuItems.tsx +++ b/src/components/LibraryMenuItems.tsx @@ -12,6 +12,7 @@ import { MIME_TYPES } from "../constants"; import Spinner from "./Spinner"; import LibraryMenuBrowseButton from "./LibraryMenuBrowseButton"; import clsx from "clsx"; +import { duplicateElements } from "../element/newElement"; const CELLS_PER_ROW = 4; @@ -96,7 +97,14 @@ const LibraryMenuItems = ({ } else { targetElements = libraryItems.filter((item) => item.id === id); } - return targetElements; + return targetElements.map((item) => { + return { + ...item, + // duplicate each library item before inserting on canvas to confine + // ids and bindings to each library item. See #6465 + elements: duplicateElements(item.elements), + }; + }); }; const createLibraryItemCompo = (params: { From e7e54814e7fef6fbd89dbb6e740230c6df2a932f Mon Sep 17 00:00:00 2001 From: Excalidraw Bot <77840495+excalibot@users.noreply.github.com> Date: Sun, 16 Apr 2023 17:12:37 +0200 Subject: [PATCH 027/451] chore: Update translations from Crowdin (#6290) * New translations en.json (Occitan) * New translations en.json (Kabyle) * Auto commit: Calculate translation coverage * New translations en.json (Romanian) * New translations en.json (French) * New translations en.json (Slovenian) * New translations en.json (Norwegian Bokmal) * Auto commit: Calculate translation coverage * New translations en.json (Dutch) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Chinese Traditional) * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Galician) * Auto commit: Calculate translation coverage * New translations en.json (German) * Auto commit: Calculate translation coverage * New translations en.json (Marathi) * New translations en.json (Hindi) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Basque) * Auto commit: Calculate translation coverage * New translations en.json (Swedish) * Auto commit: Calculate translation coverage * New translations en.json (Spanish) * Auto commit: Calculate translation coverage * New translations en.json (Hebrew) * Auto commit: Calculate translation coverage * New translations en.json (Hebrew) * Auto commit: Calculate translation coverage * New translations en.json (Hebrew) * New translations en.json (Chinese Simplified) * Auto commit: Calculate translation coverage * New translations en.json (Slovak) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Turkish) * Auto commit: Calculate translation coverage * New translations en.json (Romanian) * New translations en.json (Spanish) * New translations en.json (Catalan) * New translations en.json (Basque) * New translations en.json (Finnish) * New translations en.json (Portuguese) * New translations en.json (Slovak) * New translations en.json (Chinese Simplified) * New translations en.json (Portuguese, Brazilian) * New translations en.json (Tamil) * New translations en.json (Marathi) * New translations en.json (Hindi) * New translations en.json (French) * New translations en.json (Arabic) * New translations en.json (Bulgarian) * New translations en.json (Czech) * New translations en.json (Danish) * New translations en.json (German) * New translations en.json (Greek) * New translations en.json (Hebrew) * New translations en.json (Hungarian) * New translations en.json (Italian) * New translations en.json (Japanese) * New translations en.json (Korean) * New translations en.json (Kurdish) * New translations en.json (Lithuanian) * New translations en.json (Dutch) * New translations en.json (Punjabi) * New translations en.json (Polish) * New translations en.json (Russian) * New translations en.json (Slovenian) * New translations en.json (Swedish) * New translations en.json (Turkish) * New translations en.json (Ukrainian) * New translations en.json (Chinese Traditional) * New translations en.json (Vietnamese) * New translations en.json (Galician) * New translations en.json (Indonesian) * New translations en.json (Persian) * New translations en.json (Bengali) * New translations en.json (Norwegian Nynorsk) * New translations en.json (Kazakh) * New translations en.json (Latvian) * New translations en.json (Burmese) * New translations en.json (Chinese Traditional, Hong Kong) * New translations en.json (Sinhala) * New translations en.json (Norwegian Bokmal) * New translations en.json (Occitan) * New translations en.json (Kabyle) * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Chinese Simplified) * New translations en.json (Greek) * New translations en.json (Slovenian) * New translations en.json (Swedish) * New translations en.json (Norwegian Bokmal) * Auto commit: Calculate translation coverage * New translations en.json (Romanian) * Auto commit: Calculate translation coverage * New translations en.json (Chinese Traditional) * Auto commit: Calculate translation coverage * New translations en.json (Portuguese) * Auto commit: Calculate translation coverage * New translations en.json (Portuguese) * New translations en.json (German) * Auto commit: Calculate translation coverage * New translations en.json (Galician) * Auto commit: Calculate translation coverage * New translations en.json (Galician) * Auto commit: Calculate translation coverage * New translations en.json (Hebrew) * Auto commit: Calculate translation coverage * New translations en.json (Hebrew) * New translations en.json (French) * Auto commit: Calculate translation coverage * New translations en.json (Indonesian) * Auto commit: Calculate translation coverage * New translations en.json (Indonesian) * Auto commit: Calculate translation coverage * New translations en.json (Italian) * New translations en.json (Chinese Simplified) * New translations en.json (Chinese Simplified) * New translations en.json (Kabyle) * Auto commit: Calculate translation coverage * New translations en.json (Kabyle) * Auto commit: Calculate translation coverage * New translations en.json (Marathi) * New translations en.json (Hindi) * Auto commit: Calculate translation coverage * New translations en.json (Hindi) * Auto commit: Calculate translation coverage * New translations en.json (Slovak) * Auto commit: Calculate translation coverage * New translations en.json (Spanish) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Thai) * Auto commit: Calculate translation coverage * New translations en.json (Japanese) * Auto commit: Calculate translation coverage * New translations en.json (Dutch) * Auto commit: Calculate translation coverage * New translations en.json (Dutch) * Auto commit: Calculate translation coverage * New translations en.json (Basque) * Auto commit: Calculate translation coverage * New translations en.json (Basque) * Auto commit: Calculate translation coverage * New translations en.json (Marathi) * Auto commit: Calculate translation coverage * New translations en.json (Marathi) * Auto commit: Calculate translation coverage * New translations en.json (Marathi) * New translations en.json (Hindi) * Auto commit: Calculate translation coverage * New translations en.json (Polish) * Auto commit: Calculate translation coverage * New translations en.json (Polish) * New translations en.json (Chinese Simplified) * New translations en.json (Vietnamese) * Auto commit: Calculate translation coverage * New translations en.json (Vietnamese) * Auto commit: Calculate translation coverage * New translations en.json (Polish) * Auto commit: Calculate translation coverage * New translations en.json (Korean) * Auto commit: Calculate translation coverage * New translations en.json (Dutch) * New translations en.json (Basque) * New translations en.json (Marathi) * New translations en.json (Hindi) * New translations en.json (Polish) * New translations en.json (Chinese Simplified) * New translations en.json (Vietnamese) * New translations en.json (Korean) * New translations en.json (Romanian) * New translations en.json (French) * New translations en.json (Spanish) * New translations en.json (Arabic) * New translations en.json (Bulgarian) * New translations en.json (Catalan) * New translations en.json (Czech) * New translations en.json (Danish) * New translations en.json (German) * New translations en.json (Greek) * New translations en.json (Finnish) * New translations en.json (Hebrew) * New translations en.json (Hungarian) * New translations en.json (Italian) * New translations en.json (Japanese) * New translations en.json (Kurdish) * New translations en.json (Lithuanian) * New translations en.json (Punjabi) * New translations en.json (Portuguese) * New translations en.json (Russian) * New translations en.json (Slovak) * New translations en.json (Slovenian) * New translations en.json (Swedish) * New translations en.json (Turkish) * New translations en.json (Ukrainian) * New translations en.json (Chinese Traditional) * New translations en.json (Galician) * New translations en.json (Portuguese, Brazilian) * New translations en.json (Indonesian) * New translations en.json (Persian) * New translations en.json (Tamil) * New translations en.json (Bengali) * New translations en.json (Thai) * New translations en.json (Norwegian Nynorsk) * New translations en.json (Kazakh) * New translations en.json (Latvian) * New translations en.json (Burmese) * New translations en.json (Chinese Traditional, Hong Kong) * New translations en.json (Sinhala) * New translations en.json (Norwegian Bokmal) * New translations en.json (Occitan) * New translations en.json (Kabyle) * Auto commit: Calculate translation coverage * New translations en.json (Slovenian) * New translations en.json (Norwegian Bokmal) * Auto commit: Calculate translation coverage * New translations en.json (Japanese) * Auto commit: Calculate translation coverage * New translations en.json (German) * Auto commit: Calculate translation coverage * New translations en.json (Chinese Traditional) * Auto commit: Calculate translation coverage * New translations en.json (Marathi) * New translations en.json (Hindi) * Auto commit: Calculate translation coverage * New translations en.json (Romanian) * Auto commit: Calculate translation coverage * New translations en.json (Italian) * Auto commit: Calculate translation coverage * New translations en.json (Turkish) * Auto commit: Calculate translation coverage --- src/locales/ar-SA.json | 21 +- src/locales/bg-BG.json | 21 +- src/locales/bn-BD.json | 21 +- src/locales/ca-ES.json | 21 +- src/locales/cs-CZ.json | 21 +- src/locales/da-DK.json | 21 +- src/locales/de-DE.json | 21 +- src/locales/el-GR.json | 21 +- src/locales/es-ES.json | 21 +- src/locales/eu-ES.json | 21 +- src/locales/fa-IR.json | 21 +- src/locales/fi-FI.json | 21 +- src/locales/fr-FR.json | 21 +- src/locales/gl-ES.json | 23 +- src/locales/he-IL.json | 307 +++++++++++----------- src/locales/hi-IN.json | 21 +- src/locales/hu-HU.json | 21 +- src/locales/id-ID.json | 23 +- src/locales/it-IT.json | 21 +- src/locales/ja-JP.json | 21 +- src/locales/kab-KAB.json | 33 ++- src/locales/kk-KZ.json | 21 +- src/locales/ko-KR.json | 37 ++- src/locales/ku-TR.json | 21 +- src/locales/lt-LT.json | 21 +- src/locales/lv-LV.json | 21 +- src/locales/mr-IN.json | 21 +- src/locales/my-MM.json | 21 +- src/locales/nb-NO.json | 21 +- src/locales/nl-NL.json | 47 ++-- src/locales/nn-NO.json | 21 +- src/locales/oc-FR.json | 21 +- src/locales/pa-IN.json | 21 +- src/locales/percentages.json | 79 +++--- src/locales/pl-PL.json | 77 +++--- src/locales/pt-BR.json | 21 +- src/locales/pt-PT.json | 21 +- src/locales/ro-RO.json | 21 +- src/locales/ru-RU.json | 21 +- src/locales/si-LK.json | 21 +- src/locales/sk-SK.json | 21 +- src/locales/sl-SI.json | 21 +- src/locales/sv-SE.json | 21 +- src/locales/ta-IN.json | 21 +- src/locales/th-TH.json | 482 +++++++++++++++++++++++++++++++++++ src/locales/tr-TR.json | 31 ++- src/locales/uk-UA.json | 21 +- src/locales/vi-VN.json | 267 ++++++++++--------- src/locales/zh-CN.json | 27 +- src/locales/zh-HK.json | 21 +- src/locales/zh-TW.json | 21 +- 51 files changed, 1784 insertions(+), 468 deletions(-) create mode 100644 src/locales/th-TH.json diff --git a/src/locales/ar-SA.json b/src/locales/ar-SA.json index 6c6c0cf39..25a32f222 100644 --- a/src/locales/ar-SA.json +++ b/src/locales/ar-SA.json @@ -110,6 +110,7 @@ "increaseFontSize": "تكبير حجم الخط", "unbindText": "فك ربط النص", "bindText": "ربط النص بالحاوية", + "createContainerFromText": "", "link": { "edit": "تعديل الرابط", "create": "إنشاء رابط", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "تعذر الاتصال بخادم التعاون. الرجاء إعادة تحميل الصفحة والمحاولة مرة أخرى.", "importLibraryError": "تعذر تحميل المكتبة", "collabSaveFailed": "تعذر الحفظ في قاعدة البيانات. إذا استمرت المشاكل، يفضل أن تحفظ ملفك محليا كي لا تفقد عملك.", - "collabSaveFailed_sizeExceeded": "تعذر الحفظ في قاعدة البيانات، يبدو أن القماش كبير للغاية، يفضّل حفظ الملف محليا كي لا تفقد عملك." + "collabSaveFailed_sizeExceeded": "تعذر الحفظ في قاعدة البيانات، يبدو أن القماش كبير للغاية، يفضّل حفظ الملف محليا كي لا تفقد عملك.", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "تحديد", @@ -303,7 +319,8 @@ "doubleClick": "انقر مرتين", "drag": "اسحب", "editor": "المحرر", - "editSelectedShape": "تعديل الشكل المحدد (النص/السهم/الخط)", + "editLineArrowPoints": "", + "editText": "", "github": "عثرت على مشكلة؟ إرسال", "howto": "اتبع التعليمات", "or": "أو", diff --git a/src/locales/bg-BG.json b/src/locales/bg-BG.json index ba052783d..501ce7399 100644 --- a/src/locales/bg-BG.json +++ b/src/locales/bg-BG.json @@ -110,6 +110,7 @@ "increaseFontSize": "", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { "edit": "", "create": "", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Селекция", @@ -303,7 +319,8 @@ "doubleClick": "", "drag": "плъзнете", "editor": "Редактор", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "Намерихте проблем? Изпратете", "howto": "Следвайте нашите ръководства", "or": "или", diff --git a/src/locales/bn-BD.json b/src/locales/bn-BD.json index 47c6f02b2..a5d9dec0f 100644 --- a/src/locales/bn-BD.json +++ b/src/locales/bn-BD.json @@ -110,6 +110,7 @@ "increaseFontSize": "লেখনীর মাত্রা বাড়ান", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { "edit": "লিঙ্ক সংশোধন", "create": "লিঙ্ক তৈরী", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "কোল্যাব সার্ভারের সাথে সংযোগ করা যায়নি। পৃষ্ঠাটি পুনরায় লোড করে আবার চেষ্টা করুন।", "importLibraryError": "সংগ্রহ লোড করা যায়নি", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "বাছাই", @@ -303,7 +319,8 @@ "doubleClick": "", "drag": "", "editor": "", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "", "howto": "", "or": "অথবা", diff --git a/src/locales/ca-ES.json b/src/locales/ca-ES.json index e94523b29..ae45e764d 100644 --- a/src/locales/ca-ES.json +++ b/src/locales/ca-ES.json @@ -110,6 +110,7 @@ "increaseFontSize": "Augmenta la mida de la lletra", "unbindText": "Desvincular el text", "bindText": "Ajusta el text al contenidor", + "createContainerFromText": "", "link": { "edit": "Edita l'enllaç", "create": "Crea un enllaç", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "No ha estat possible connectar amb el servidor collab. Si us plau recarregueu la pàgina i torneu a provar.", "importLibraryError": "No s'ha pogut carregar la biblioteca", "collabSaveFailed": "No s'ha pogut desar a la base de dades de fons. Si els problemes persisteixen, hauríeu de desar el fitxer localment per assegurar-vos que no perdeu el vostre treball.", - "collabSaveFailed_sizeExceeded": "No s'ha pogut desar a la base de dades de fons, sembla que el llenç és massa gran. Hauríeu de desar el fitxer localment per assegurar-vos que no perdeu el vostre treball." + "collabSaveFailed_sizeExceeded": "No s'ha pogut desar a la base de dades de fons, sembla que el llenç és massa gran. Hauríeu de desar el fitxer localment per assegurar-vos que no perdeu el vostre treball.", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Selecció", @@ -303,7 +319,8 @@ "doubleClick": "doble clic", "drag": "arrossega", "editor": "Editor", - "editSelectedShape": "Edita la forma seleccionada (text, fletxa o línia)", + "editLineArrowPoints": "", + "editText": "", "github": "Hi heu trobat un problema? Informeu-ne", "howto": "Seguiu les nostres guies", "or": "o", diff --git a/src/locales/cs-CZ.json b/src/locales/cs-CZ.json index 718d974b2..d57a8837d 100644 --- a/src/locales/cs-CZ.json +++ b/src/locales/cs-CZ.json @@ -110,6 +110,7 @@ "increaseFontSize": "Zvětšit písmo", "unbindText": "Zrušit vazbu textu", "bindText": "Vázat text s kontejnerem", + "createContainerFromText": "", "link": { "edit": "Upravit odkaz", "create": "Vytvořit odkaz", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Výběr", @@ -303,7 +319,8 @@ "doubleClick": "dvojklik", "drag": "tažení", "editor": "Editor", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "", "howto": "", "or": "nebo", diff --git a/src/locales/da-DK.json b/src/locales/da-DK.json index 8e541f90d..c8b5ad6e3 100644 --- a/src/locales/da-DK.json +++ b/src/locales/da-DK.json @@ -110,6 +110,7 @@ "increaseFontSize": "", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { "edit": "", "create": "", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "", @@ -303,7 +319,8 @@ "doubleClick": "", "drag": "", "editor": "", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "", "howto": "", "or": "", diff --git a/src/locales/de-DE.json b/src/locales/de-DE.json index b389fe5a4..bdf30a371 100644 --- a/src/locales/de-DE.json +++ b/src/locales/de-DE.json @@ -110,6 +110,7 @@ "increaseFontSize": "Schrift vergrößern", "unbindText": "Text lösen", "bindText": "Text an Container binden", + "createContainerFromText": "Text in Container einbetten", "link": { "edit": "Link bearbeiten", "create": "Link erstellen", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Konnte keine Verbindung zum Collab-Server herstellen. Bitte lade die Seite neu und versuche es erneut.", "importLibraryError": "Bibliothek konnte nicht geladen werden", "collabSaveFailed": "Keine Speicherung in der Backend-Datenbank möglich. Wenn die Probleme weiterhin bestehen, solltest Du Deine Datei lokal speichern, um sicherzustellen, dass Du Deine Arbeit nicht verlierst.", - "collabSaveFailed_sizeExceeded": "Keine Speicherung in der Backend-Datenbank möglich, die Zeichenfläche scheint zu groß zu sein. Du solltest Deine Datei lokal speichern, um sicherzustellen, dass Du Deine Arbeit nicht verlierst." + "collabSaveFailed_sizeExceeded": "Keine Speicherung in der Backend-Datenbank möglich, die Zeichenfläche scheint zu groß zu sein. Du solltest Deine Datei lokal speichern, um sicherzustellen, dass Du Deine Arbeit nicht verlierst.", + "brave_measure_text_error": { + "start": "Sieht so aus, als ob du den Brave Browser benutzt mit der", + "aggressive_block_fingerprint": "\"Fingerprinting aggressiv blockieren\"", + "setting_enabled": "Einstellung aktiviert", + "break": "Dies könnte zur inkorrekten Darstellung der", + "text_elements": "Textelemente", + "in_your_drawings": "in deinen Zeichnungen führen", + "strongly_recommend": "Wir empfehlen dringend, diese Einstellung zu deaktivieren. Du kannst", + "steps": "diesen Schritten entsprechend", + "how": "folgen", + "disable_setting": " Wenn die Deaktivierung dieser Einstellung nicht zu einer korrekten Textdarstellung führt, öffne bitte einen", + "issue": "Issue", + "write": "auf GitHub, oder schreibe uns auf", + "discord": "Discord" + } }, "toolBar": { "selection": "Auswahl", @@ -303,7 +319,8 @@ "doubleClick": "doppelklicken", "drag": "ziehen", "editor": "Editor", - "editSelectedShape": "Ausgewählte Form bearbeiten (Text/Pfeil/Linie)", + "editLineArrowPoints": "Linien-/Pfeil-Punkte bearbeiten", + "editText": "Text bearbeiten / Label hinzufügen", "github": "Ein Problem gefunden? Informiere uns", "howto": "Folge unseren Anleitungen", "or": "oder", diff --git a/src/locales/el-GR.json b/src/locales/el-GR.json index d478be3e7..888c39568 100644 --- a/src/locales/el-GR.json +++ b/src/locales/el-GR.json @@ -110,6 +110,7 @@ "increaseFontSize": "Αύξηση μεγέθους γραμματοσειράς", "unbindText": "Αποσύνδεση κειμένου", "bindText": "Δέσμευση κειμένου στο δοχείο", + "createContainerFromText": "", "link": { "edit": "Επεξεργασία συνδέσμου", "create": "Δημιουργία συνδέσμου", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Αδυναμία σύνδεσης με τον διακομιστή συνεργασίας. Παρακαλώ ανανεώστε τη σελίδα και προσπαθήστε ξανά.", "importLibraryError": "Αδυναμία φόρτωσης βιβλιοθήκης", "collabSaveFailed": "Η αποθήκευση στη βάση δεδομένων δεν ήταν δυνατή. Αν το προβλήματα παραμείνει, θα πρέπει να αποθηκεύσετε το αρχείο σας τοπικά για να βεβαιωθείτε ότι δεν χάνετε την εργασία σας.", - "collabSaveFailed_sizeExceeded": "Η αποθήκευση στη βάση δεδομένων δεν ήταν δυνατή, ο καμβάς φαίνεται να είναι πολύ μεγάλος. Θα πρέπει να αποθηκεύσετε το αρχείο τοπικά για να βεβαιωθείτε ότι δεν θα χάσετε την εργασία σας." + "collabSaveFailed_sizeExceeded": "Η αποθήκευση στη βάση δεδομένων δεν ήταν δυνατή, ο καμβάς φαίνεται να είναι πολύ μεγάλος. Θα πρέπει να αποθηκεύσετε το αρχείο τοπικά για να βεβαιωθείτε ότι δεν θα χάσετε την εργασία σας.", + "brave_measure_text_error": { + "start": "Φαίνεται ότι χρησιμοποιείτε το Brave browser με το", + "aggressive_block_fingerprint": "Αποκλεισμός \"Δακτυλικών Αποτυπωμάτων\"", + "setting_enabled": "ρύθμιση ενεργοποιημένη", + "break": "Αυτό θα μπορούσε να σπάσει το", + "text_elements": "Στοιχεία Κειμένου", + "in_your_drawings": "στα σχέδιά σας", + "strongly_recommend": "Συνιστούμε να απενεργοποιήσετε αυτή τη ρύθμιση. Μπορείτε να ακολουθήσετε", + "steps": "αυτά τα βήματα", + "how": "για το πώς να το κάνετε", + "disable_setting": " Εάν η απενεργοποίηση αυτής της ρύθμισης δεν διορθώνει την εμφάνιση των στοιχείων κειμένου, παρακαλώ ανοίξτε ένα", + "issue": "πρόβλημα", + "write": "στο GitHub, ή γράψτε μας στο", + "discord": "Discord" + } }, "toolBar": { "selection": "Επιλογή", @@ -303,7 +319,8 @@ "doubleClick": "διπλό κλικ", "drag": "σύρε", "editor": "Επεξεργαστής", - "editSelectedShape": "Επεξεργασία επιλεγμένου σχήματος (κείμενο/βέλος/γραμμή)", + "editLineArrowPoints": "", + "editText": "", "github": "Βρήκατε πρόβλημα; Υποβάλετε το", "howto": "Ακολουθήστε τους οδηγούς μας", "or": "ή", diff --git a/src/locales/es-ES.json b/src/locales/es-ES.json index eceb38ae3..67a110293 100644 --- a/src/locales/es-ES.json +++ b/src/locales/es-ES.json @@ -110,6 +110,7 @@ "increaseFontSize": "Aumentar el tamaño de letra", "unbindText": "Desvincular texto", "bindText": "Vincular texto al contenedor", + "createContainerFromText": "Envolver el texto en un contenedor", "link": { "edit": "Editar enlace", "create": "Crear enlace", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "No se pudo conectar al servidor colaborador. Por favor, vuelva a cargar la página y vuelva a intentarlo.", "importLibraryError": "No se pudo cargar la librería", "collabSaveFailed": "No se pudo guardar en la base de datos del backend. Si los problemas persisten, debería guardar su archivo localmente para asegurarse de que no pierde su trabajo.", - "collabSaveFailed_sizeExceeded": "No se pudo guardar en la base de datos del backend, el lienzo parece ser demasiado grande. Debería guardar el archivo localmente para asegurarse de que no pierde su trabajo." + "collabSaveFailed_sizeExceeded": "No se pudo guardar en la base de datos del backend, el lienzo parece ser demasiado grande. Debería guardar el archivo localmente para asegurarse de que no pierde su trabajo.", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "ajuste activado", + "break": "Esto podría resultar en romper los", + "text_elements": "Elementos de texto", + "in_your_drawings": "en tus dibujos", + "strongly_recommend": "Recomendamos desactivar esta configuración. Puedes seguir", + "steps": "estos pasos", + "how": "sobre cómo hacerlo", + "disable_setting": " Si deshabilitar esta opción no arregla la visualización de elementos de texto, por favor abre un", + "issue": "issue", + "write": "en GitHub, o escríbenos en", + "discord": "Discord" + } }, "toolBar": { "selection": "Selección", @@ -303,7 +319,8 @@ "doubleClick": "doble clic", "drag": "arrastrar", "editor": "Editor", - "editSelectedShape": "Editar la forma seleccionada (texto/flecha/línea)", + "editLineArrowPoints": "", + "editText": "", "github": "¿Ha encontrado un problema? Envíelo", "howto": "Siga nuestras guías", "or": "o", diff --git a/src/locales/eu-ES.json b/src/locales/eu-ES.json index d35baf4e4..1aec330cb 100644 --- a/src/locales/eu-ES.json +++ b/src/locales/eu-ES.json @@ -110,6 +110,7 @@ "increaseFontSize": "Handitu letra tamaina", "unbindText": "Askatu testua", "bindText": "Lotu testua edukiontziari", + "createContainerFromText": "Bilatu testua edukiontzi batean", "link": { "edit": "Editatu esteka", "create": "Sortu esteka", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Ezin izan da elkarlaneko zerbitzarira konektatu. Mesedez, berriro kargatu orria eta saiatu berriro.", "importLibraryError": "Ezin izan da liburutegia kargatu", "collabSaveFailed": "Ezin izan da backend datu-basean gorde. Arazoak jarraitzen badu, zure fitxategia lokalean gorde beharko zenuke zure lana ez duzula galtzen ziurtatzeko.", - "collabSaveFailed_sizeExceeded": "Ezin izan da backend datu-basean gorde, ohiala handiegia dela dirudi. Fitxategia lokalean gorde beharko zenuke zure lana galtzen ez duzula ziurtatzeko." + "collabSaveFailed_sizeExceeded": "Ezin izan da backend datu-basean gorde, ohiala handiegia dela dirudi. Fitxategia lokalean gorde beharko zenuke zure lana galtzen ez duzula ziurtatzeko.", + "brave_measure_text_error": { + "start": "Brave nabigatzailea erabiltzen ari zarela dirudi", + "aggressive_block_fingerprint": "Aggressively Block Fingerprinting", + "setting_enabled": "ezarpena gaituta", + "break": "Honek honen haustea eragin dezake", + "text_elements": "Testu-elementuak", + "in_your_drawings": "zure marrazkietan", + "strongly_recommend": "Ezarpen hau desgaitzea gomendatzen dugu. Jarrai dezakezu", + "steps": "urrats hauek", + "how": "jakiteko nola egin", + "disable_setting": " Ezarpen hau desgaitzeak testu-elementuen bistaratzea konpontzen ez badu, ireki", + "issue": "eskaera (issue) bat", + "write": "gure Github-en edo idatz iezaguzu", + "discord": "Discord-en" + } }, "toolBar": { "selection": "Hautapena", @@ -303,7 +319,8 @@ "doubleClick": "klik bikoitza", "drag": "arrastatu", "editor": "Editorea", - "editSelectedShape": "Editatu hautatutako forma (testua/gezia/lerroa)", + "editLineArrowPoints": "", + "editText": "", "github": "Arazorik izan al duzu? Eman horren berri", "howto": "Jarraitu gure gidak", "or": "edo", diff --git a/src/locales/fa-IR.json b/src/locales/fa-IR.json index cc7de0dee..44cf7ae00 100644 --- a/src/locales/fa-IR.json +++ b/src/locales/fa-IR.json @@ -110,6 +110,7 @@ "increaseFontSize": "افزایش دادن اندازه فونت", "unbindText": "بازکردن نوشته", "bindText": "بستن نوشته", + "createContainerFromText": "", "link": { "edit": "ویرایش لینک", "create": "ایجاد پیوند", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "به سرور collab متصل نشد. لطفا صفحه را مجددا بارگذاری کنید و دوباره تلاش کنید.", "importLibraryError": "داده‌ها بارگذاری نشدند", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "گزینش", @@ -303,7 +319,8 @@ "doubleClick": "دابل کلیک", "drag": "کشیدن", "editor": "ویرایشگر", - "editSelectedShape": "ویرایش شکل انتخاب شده (متن/فلش/خط)", + "editLineArrowPoints": "", + "editText": "", "github": "اشکالی می بینید؟ گزارش دهید", "howto": "راهنمای ما را دنبال کنید", "or": "یا", diff --git a/src/locales/fi-FI.json b/src/locales/fi-FI.json index 6c357b167..e0701f2d2 100644 --- a/src/locales/fi-FI.json +++ b/src/locales/fi-FI.json @@ -110,6 +110,7 @@ "increaseFontSize": "Kasvata kirjasinkokoa", "unbindText": "Irroita teksti", "bindText": "Kiinnitä teksti säiliöön", + "createContainerFromText": "", "link": { "edit": "Muokkaa linkkiä", "create": "Luo linkki", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Yhteyden muodostaminen collab-palvelimeen epäonnistui. Virkistä sivu ja yritä uudelleen.", "importLibraryError": "Kokoelman lataaminen epäonnistui", "collabSaveFailed": "Ei voitu tallentaan palvelimen tietokantaan. Jos ongelmia esiintyy, sinun kannatta tallentaa tallentaa tiedosto paikallisesti varmistaaksesi, että et menetä työtäsi.", - "collabSaveFailed_sizeExceeded": "Ei voitu tallentaan palvelimen tietokantaan. Jos ongelmia esiintyy, sinun kannatta tallentaa tallentaa tiedosto paikallisesti varmistaaksesi, että et menetä työtäsi." + "collabSaveFailed_sizeExceeded": "Ei voitu tallentaan palvelimen tietokantaan. Jos ongelmia esiintyy, sinun kannatta tallentaa tallentaa tiedosto paikallisesti varmistaaksesi, että et menetä työtäsi.", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Valinta", @@ -303,7 +319,8 @@ "doubleClick": "kaksoisnapsautus", "drag": "vedä", "editor": "Muokkausohjelma", - "editSelectedShape": "Muokkaa valittua muotoa (teksti/nuoli/viiva)", + "editLineArrowPoints": "", + "editText": "", "github": "Löysitkö ongelman? Kerro meille", "howto": "Seuraa oppaitamme", "or": "tai", diff --git a/src/locales/fr-FR.json b/src/locales/fr-FR.json index 573e3fd1a..49135c3b6 100644 --- a/src/locales/fr-FR.json +++ b/src/locales/fr-FR.json @@ -110,6 +110,7 @@ "increaseFontSize": "Augmenter la taille de la police", "unbindText": "Dissocier le texte", "bindText": "Associer le texte au conteneur", + "createContainerFromText": "Encadrer le texte dans un conteneur", "link": { "edit": "Modifier le lien", "create": "Ajouter un lien", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Impossible de se connecter au serveur collaboratif. Veuillez recharger la page et réessayer.", "importLibraryError": "Impossible de charger la bibliothèque", "collabSaveFailed": "Impossible d'enregistrer dans la base de données en arrière-plan. Si des problèmes persistent, vous devriez enregistrer votre fichier localement pour vous assurer de ne pas perdre votre travail.", - "collabSaveFailed_sizeExceeded": "Impossible d'enregistrer dans la base de données en arrière-plan, le tableau semble trop grand. Vous devriez enregistrer le fichier localement pour vous assurer de ne pas perdre votre travail." + "collabSaveFailed_sizeExceeded": "Impossible d'enregistrer dans la base de données en arrière-plan, le tableau semble trop grand. Vous devriez enregistrer le fichier localement pour vous assurer de ne pas perdre votre travail.", + "brave_measure_text_error": { + "start": "Il semble que vous utilisiez le navigateur Brave avec le", + "aggressive_block_fingerprint": "blocage d'empreinte agressif", + "setting_enabled": "activé", + "break": "Ceci pourrait avoir pour conséquence de « casser » les", + "text_elements": "éléments texte", + "in_your_drawings": "dans vos dessins", + "strongly_recommend": "Nous recommandons fortement de désactiver ce paramètre. Vous pouvez suivre", + "steps": "ces étapes", + "how": "sur la manière de procéder", + "disable_setting": " Si la désactivation de ce paramètre ne résout pas l'affichage des éléments texte, veuillez ouvrir un", + "issue": "ticket", + "write": "sur notre GitHub, ou nous écrire sur", + "discord": "Discord" + } }, "toolBar": { "selection": "Sélection", @@ -303,7 +319,8 @@ "doubleClick": "double-clic", "drag": "glisser", "editor": "Éditeur", - "editSelectedShape": "Modifier la forme sélectionnée (texte/flèche/ligne)", + "editLineArrowPoints": "", + "editText": "", "github": "Problème trouvé ? Soumettre", "howto": "Suivez nos guides", "or": "ou", diff --git a/src/locales/gl-ES.json b/src/locales/gl-ES.json index 373fe4032..5571f3f15 100644 --- a/src/locales/gl-ES.json +++ b/src/locales/gl-ES.json @@ -110,6 +110,7 @@ "increaseFontSize": "Aumentar o tamaño da fonte", "unbindText": "Desvincular texto", "bindText": "Ligar o texto ao contedor", + "createContainerFromText": "Envolver o texto nun contedor", "link": { "edit": "Editar ligazón", "create": "Crear ligazón", @@ -193,7 +194,7 @@ "resetLibrary": "Isto limpará a súa biblioteca. Está seguro?", "removeItemsFromsLibrary": "Eliminar {{count}} elemento(s) da biblioteca?", "invalidEncryptionKey": "A clave de cifrado debe ter 22 caracteres. A colaboración en directo está desactivada.", - "collabOfflineWarning": "" + "collabOfflineWarning": "Non hai conexión a Internet dispoñible.\nOs teus cambios non serán gardados!" }, "errors": { "unsupportedFileType": "Tipo de ficheiro non soportado.", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Non se puido conectar ao servidor de colaboración. Por favor recargue a páxina e probe de novo.", "importLibraryError": "Non se puido cargar a biblioteca", "collabSaveFailed": "Non se puido gardar na base de datos. Se o problema persiste, deberías gardar o teu arquivo de maneira local para asegurarte de non perdelo teu traballo.", - "collabSaveFailed_sizeExceeded": "Non se puido gardar na base de datos, o lenzo semella demasiado grande. Deberías gardar o teu arquivo de maneira local para asegurarte de non perdelo teu traballo." + "collabSaveFailed_sizeExceeded": "Non se puido gardar na base de datos, o lenzo semella demasiado grande. Deberías gardar o teu arquivo de maneira local para asegurarte de non perdelo teu traballo.", + "brave_measure_text_error": { + "start": "Semella que estás usando o navegador Brave coa opción", + "aggressive_block_fingerprint": "Aggressively Block Fingerprinting", + "setting_enabled": "activada", + "break": "Isto podería provocar unha ruptura dos", + "text_elements": "Elementos de Texto", + "in_your_drawings": "nos seus debuxos", + "strongly_recommend": "Recomendámoslle encarecidamente que desactive esa opción. Pode seguir", + "steps": "estes pasos", + "how": "sobre como facelo", + "disable_setting": " Se ao desactivar esta opción non se arranxa o problema ao mostrar os elementos de texto, por favor abra unha", + "issue": "issue", + "write": "no noso GitHub, ou escríbenos ao", + "discord": "Discord" + } }, "toolBar": { "selection": "Selección", @@ -303,7 +319,8 @@ "doubleClick": "dobre-clic", "drag": "arrastrar", "editor": "Editor", - "editSelectedShape": "Editar a forma seleccionada (texto/frecha/liña)", + "editLineArrowPoints": "", + "editText": "", "github": "Encontrou un problema? Envíeo", "howto": "Sigue as nosas normas", "or": "ou", diff --git a/src/locales/he-IL.json b/src/locales/he-IL.json index 9414da375..810fc1776 100644 --- a/src/locales/he-IL.json +++ b/src/locales/he-IL.json @@ -1,18 +1,18 @@ { "labels": { "paste": "הדבק", - "pasteAsPlaintext": "", + "pasteAsPlaintext": "הדבק ללא עיצוב", "pasteCharts": "הדבק גרפים", "selectAll": "בחר הכל", - "multiSelect": "הוסף אובייקט לבחירה", + "multiSelect": "הוסף רכיב לבחירה", "moveCanvas": "הזז את הקנבס", - "cut": "חתוך", + "cut": "גזור", "copy": "העתק", "copyAsPng": "העתק ללוח כ PNG", "copyAsSvg": "העתק ללוח כ SVG", - "copyText": "העתק ללוח כ-PNG", + "copyText": "העתק ללוח כטקסט", "bringForward": "הבא שכבה קדימה", - "sendToBack": "העבר לסוף", + "sendToBack": "שלח אחורה", "bringToFront": "העבר לחזית", "sendBackward": "העבר שכבה אחורה", "delete": "מחק", @@ -26,7 +26,7 @@ "strokeStyle_solid": "מלא", "strokeStyle_dashed": "מקווקו", "strokeStyle_dotted": "מנוקד", - "sloppiness": "סגנון", + "sloppiness": "רישול", "opacity": "אטימות", "textAlign": "יישור טקסט", "edges": "קצוות", @@ -35,57 +35,57 @@ "arrowheads": "ראשי חצים", "arrowhead_none": "ללא", "arrowhead_arrow": "חץ", - "arrowhead_bar": "שורה", + "arrowhead_bar": "קצה אנכי", "arrowhead_dot": "נקודה", "arrowhead_triangle": "משולש", "fontSize": "גודל גופן", - "fontFamily": "סוג הגופן", + "fontFamily": "גופן", "onlySelected": "רק מה שנבחר", "withBackground": "רקע", "exportEmbedScene": "הטמעה של מידע הסצנה", - "exportEmbedScene_details": "מידע התצוגה יישמר לקובץ המיוצא מסוג PNG/SVG כך שיהיה ניתן לשחזרה ממנו.\nהפעולה תגדיל את גודל הקובץ המיוצא.", + "exportEmbedScene_details": "הייצוא יבוצע לקובץ מסוג PNG/SVG כדי שהמידע על הסצנה ישמר בו וניתן יהיה לבצע שחזור ממנו.\nיגדיל את גודל הקובץ של הייצוא.", "addWatermark": "הוסף \"נוצר באמצעות Excalidraw\"", - "handDrawn": "כתב יד", + "handDrawn": "ציור יד", "normal": "רגיל", "code": "קוד", "small": "קטן", - "medium": "בנוני", + "medium": "בינוני", "large": "גדול", - "veryLarge": "ענק", + "veryLarge": "גדול מאוד", "solid": "מוצק", - "hachure": "קווים משופעים", - "crossHatch": "קווים מוצלבים", + "hachure": "קווים מקבילים קצרים להצגת כיוון וחדות שיפוע במפה", + "crossHatch": "קווים מוצלבים שתי וערב", "thin": "דק", "bold": "מודגש", "left": "שמאל", "center": "מרכז", "right": "ימין", - "extraBold": "עבה", + "extraBold": "מודגש במיוחד", "architect": "ארכיטקט", "artist": "אמן", "cartoonist": "קריקטוריסט", "fileTitle": "שם קובץ", - "colorPicker": "בחירת צבע", + "colorPicker": "בוחר צבעים", "canvasColors": "בשימוש בקנבס", - "canvasBackground": "רקע הלוח", - "drawingCanvas": "לוח ציור", + "canvasBackground": "רקע קנבס", + "drawingCanvas": "קנבס ציור", "layers": "שכבות", "actions": "פעולות", "language": "שפה", - "liveCollaboration": "", + "liveCollaboration": "התחל שיתוף חי...", "duplicateSelection": "שכפל", "untitled": "ללא כותרת", "name": "שם", - "yourName": "שם", + "yourName": "שמך", "madeWithExcalidraw": "נוצר באמצעות Excalidraw", - "group": "אחד לקבוצה", + "group": "קבץ", "ungroup": "פרק קבוצה", "collaborators": "שותפים", "showGrid": "הצג רשת", "addToLibrary": "הוסף לספריה", "removeFromLibrary": "הסר מספריה", "libraryLoadingMessage": "טוען ספריה…", - "libraries": "דפדף בספריות", + "libraries": "עיין בספריות", "loadingScene": "טוען תצוגה…", "align": "יישר", "alignTop": "יישר למעלה", @@ -96,28 +96,29 @@ "centerHorizontally": "מרכז אופקית", "distributeHorizontally": "חלוקה אופקית", "distributeVertically": "חלוקה אנכית", - "flipHorizontal": "סובב אופקית", - "flipVertical": "סובב אנכית", + "flipHorizontal": "הפוך אופקית", + "flipVertical": "הפוך אנכית", "viewMode": "מצב תצוגה", - "toggleExportColorScheme": "שנה את ערכת צבעי הייצוא", + "toggleExportColorScheme": "מתג ערכת צבעים לייצוא", "share": "שתף", - "showStroke": "הצג צבעי קו מתאר", - "showBackground": "הצג צבעי רקע", + "showStroke": "הצג בוחר צבע מברשת", + "showBackground": "הצג בוחר צבע רקע", "toggleTheme": "שינוי ערכת העיצוב", "personalLib": "ספריה פרטית", "excalidrawLib": "הספריה של Excalidraw", "decreaseFontSize": "הקטן את גודל הגופן", "increaseFontSize": "הגדל את גודל הגופן", "unbindText": "ביטול קיבוע הטקסט", - "bindText": "קיבוע הטקסט לאוגד", + "bindText": "קיבוע הטקסט למיכל", + "createContainerFromText": "ארוז טקסט במיכל", "link": { "edit": "עריכת קישור", "create": "יצירת קישור", "label": "קישור" }, "lineEditor": { - "edit": "", - "exit": "" + "edit": "ערוך קו", + "exit": "צא מעורך הקו" }, "elementLock": { "lock": "נעילה", @@ -125,16 +126,16 @@ "lockAll": "לנעול הכל", "unlockAll": "שחרור הכול" }, - "statusPublished": "", - "sidebarLock": "" + "statusPublished": "פורסם", + "sidebarLock": "שמור את סרגל הצד פתוח" }, "library": { - "noItems": "", - "hint_emptyLibrary": "", - "hint_emptyPrivateLibrary": "" + "noItems": "עוד לא הוספת דברים...", + "hint_emptyLibrary": "בחר משהו בקנבס כדי להוסיף אותו לכאן, או שתתקין ספריה מהספריה הציבורית מטה.", + "hint_emptyPrivateLibrary": "בחר משהו בקנבס כדי להוסיף אותו לכאן." }, "buttons": { - "clearReset": "אפס את הלוח", + "clearReset": "אפס את הקנבאס", "exportJSON": "ייצא לקובץ", "exportImage": "ייצוא התמונה...", "export": "שמור ל...", @@ -143,7 +144,7 @@ "copyToClipboard": "העתק ללוח", "copyPngToClipboard": "העתק PNG ללוח", "scale": "קנה מידה", - "save": "שמירת קובץ נוכחי", + "save": "שמור לקובץ נוכחי", "saveAs": "שמירה בשם", "load": "פתח", "getShareableLink": "קבל קישור לשיתוף", @@ -159,58 +160,73 @@ "undo": "בטל", "redo": "בצע מחדש", "resetLibrary": "איפוס ספריה", - "createNewRoom": "צור חדר", + "createNewRoom": "צור חדר חדש", "fullScreen": "מסך מלא", "darkMode": "מצב כהה", "lightMode": "מצב בהיר", "zenMode": "מצב זן", - "exitZenMode": "צא ממצב תפריט מרחף", + "exitZenMode": "צא ממצב זן", "cancel": "ביטול", "clear": "ניקוי", - "remove": "מחיקה", - "publishLibrary": "פירסום", + "remove": "הסר", + "publishLibrary": "פרסום", "submit": "שליחה", - "confirm": "לאשר" + "confirm": "אשר" }, "alerts": { - "clearReset": "פעולה זו תנקה את כל הלוח. אתה בטוח?", - "couldNotCreateShareableLink": "לא ניתן לייצר לינק לשיתוף.", - "couldNotCreateShareableLinkTooBig": "לא הצלחנו לייצר קישור לשיתוף: התצוגה גדולה מדי", - "couldNotLoadInvalidFile": "לא ניתן לטעון קובץ שאיננו תואם", + "clearReset": "פעולה זו תנקה את כל הקנבס. אתה בטוח?", + "couldNotCreateShareableLink": "יצירת קישור לשיתוף נכשל.", + "couldNotCreateShareableLinkTooBig": "יצירת קישור לשיתוף נכשל: התצוגה גדולה מדי", + "couldNotLoadInvalidFile": "טעינת קובץ לא תקין נכשלה", "importBackendFailed": "ייבוא מהשרת נכשל.", - "cannotExportEmptyCanvas": "לא ניתן לייצא לוח ריק.", - "couldNotCopyToClipboard": "לא ניתן היה להעתיק ללוח", - "decryptFailed": "לא ניתן לפענח מידע.", - "uploadedSecurly": "ההעלאה הוצפנה מקצה לקצה, ולכן שרת Excalidraw וצד שלישי לא יכולים לקרוא את התוכן.", + "cannotExportEmptyCanvas": "לא ניתן לייצא קנבאס ריק.", + "couldNotCopyToClipboard": "לא ניתן היה להעתיק ללוח.", + "decryptFailed": "פיענוח ההצפנה של המידע נכשל.", + "uploadedSecurly": "ההעלאה אובטחה באמצעות הצפנה מקצה לקצה, פירוש הדבר שהשרת של Excalidraw וגורמי צד ג׳ לא יכולים לקרוא את התוכן.", "loadSceneOverridePrompt": "טעינה של ציור חיצוני תחליף את התוכן הקיים שלך. האם תרצה להמשיך?", - "collabStopOverridePrompt": "עצירת השיתוף תוביל למחיקת התרשימים השמורים בדפדפן. האם את/ה בטוח/ה?\n(אם תרצה לשמור את התרשימים הקיימים, תוכל לסגור את הדפדפן מבלי לסיים את השיתוף.)", + "collabStopOverridePrompt": "עצירת השיתוף תוביל למחיקת הציור הקודם ששמור מקומית בדפדפן. האם אתה בטוח?\n\n(אם תרצה לשמור את הציור המקומי, סגור את הטאב של הדפדפן במקום.)", "errorAddingToLibrary": "לא ניתן להוסיף פריט לספרייה", - "errorRemovingFromLibrary": "לא ניתן למחוק פריט מהספריה", - "confirmAddLibrary": "הפעולה תוסיף {{numShapes}} צורה(ות) לספריה שלך. האם אתה בטוח?", + "errorRemovingFromLibrary": "לא ניתן להסיר פריט מהספריה", + "confirmAddLibrary": "זה יוסיף {{numShapes}} צורה(ות) לספריה שלך. האם אתה בטוח?", "imageDoesNotContainScene": "נראה שהתמונה לא מכילה מידע על הסצינה. האם אפשרת הטמעת מידע הסצינה בעת השמירה?", - "cannotRestoreFromImage": "לא הצלחנו לשחזר את התצוגה מקובץ התמונה", - "invalidSceneUrl": "ייבוא המידע מן סצינה מכתובת האינטרנט נכשלה. המידע בנוי באופן משובש או שהוא אינו קובץ JSON תקין של Excalidraw.", - "resetLibrary": "פעולה זו תנקה את כל הלוח. אתה בטוח?", - "removeItemsFromsLibrary": "מחיקת {{count}} פריטים(ים) מתוך הספריה?", - "invalidEncryptionKey": "מפתח ההצפנה חייב להיות בן 22 תוים. השיתוף החי מבוטל.", - "collabOfflineWarning": "" + "cannotRestoreFromImage": "לא הצלחנו לשחזר את הסצנה מקובץ התמונה", + "invalidSceneUrl": "ייבוא מידע סצנה מהקישור שסופק כשל. או שהוא משובש, או שאינו מכיל מידע של Excalidraw בפורמט JSON.", + "resetLibrary": "פעולה זו תנקה את כל הספריה שלך. אתה בטוח?", + "removeItemsFromsLibrary": "מחק {{count}} פריט(ים) מהספריה?", + "invalidEncryptionKey": "מפתח ההצפנה חייב להיות בן 22 תוים. השיתוף החי מנוטרל.", + "collabOfflineWarning": "אין חיבור זמין לאינטרנט.\nהשינויים שלך לא ישמרו!" }, "errors": { "unsupportedFileType": "סוג הקובץ אינו נתמך.", - "imageInsertError": "לא ניתן היה להטמיע את התמונה, אנא נסו שוב מאוחר יותר...", - "fileTooBig": "הקובץ כבד מדי. הגודל המקסימלי המותר הוא {{maxSize}}.", - "svgImageInsertError": "לא ניתן היה להטמיע את תמונת ה-SVG. קידוד ה-SVG אינו תקני.", - "invalidSVGString": "SVG בלתי תקני.", - "cannotResolveCollabServer": "", + "imageInsertError": "לא ניתן היה להוסיף את התמונה. אנא נסה שוב מאוחר יותר...", + "fileTooBig": "הקובץ גדול מדי. הגודל המירבי המותר הינו {{maxSize}}.", + "svgImageInsertError": "לא ניתן היה להוסיף את תמונת ה-SVG. הסימונים בתוך קובץ ה-SVG עשויים להיות שגויים.", + "invalidSVGString": "SVG שגוי.", + "cannotResolveCollabServer": "לא הצלחתי להתחבר לשרת השיתוף. אנא רענן את הדף ונסה שוב.", "importLibraryError": "לא ניתן היה לטעון את הספריה", - "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed": "לא הצלחתי להתחבר למסד הנתונים האחורי. אם הבעיה ממשיכה, כדאי שתשמור את הקובץ מקומית כדי לוודא שלא תאבד את העבודה שלך.", + "collabSaveFailed_sizeExceeded": "לא הצלחתי לשמור למסד הנתונים האחורי, נראה שהקנבס שלך גדול מדי. כדאי שתשמור את הקובץ מקומית כדי לוודא שלא תאבד את העבודה שלך.", + "brave_measure_text_error": { + "start": "נראה שאתה משתמש בדפדפן Brave עם ה-", + "aggressive_block_fingerprint": "חסימת Fingerprinting אגרסיבית", + "setting_enabled": "ההגדרה מופעלת", + "break": "זה יכול לגרום לבעיה ב-", + "text_elements": "רכיבי טקסט", + "in_your_drawings": "בציורים שלך", + "strongly_recommend": "אנו ממליצים בחום לנטרל את ההגדרה הזו. אתה יכול לעקוב", + "steps": "הצעדים הבאים", + "how": "כיצד לעשות את זה", + "disable_setting": " אם נטרול ההגדרה לא מתקן את תצוגת רכיבי הטקסט, אנא פתח", + "issue": "בעיה", + "write": "ב- GitHub שלנו, או כתוב לנו ב-", + "discord": "Discord" + } }, "toolBar": { "selection": "בחירה", "image": "הוספת תמונה", - "rectangle": "מרובע", - "diamond": "מעוין", + "rectangle": "מלבן", + "diamond": "יהלום", "ellipse": "אליפסה", "arrow": "חץ", "line": "קו", @@ -218,79 +234,79 @@ "text": "טקסט", "library": "ספריה", "lock": "השאר את הכלי הנבחר פעיל גם לאחר סיום הציור", - "penMode": "", - "link": "הוספה/עדכון של קישור עבור הצורה הנבחרת", + "penMode": "מצב עט - מנע נגיעה", + "link": "הוספה/עדכון קישור של הצורה שנבחרה", "eraser": "מחק", - "hand": "" + "hand": "יד (כלי הזזה)" }, "headings": { - "canvasActions": "פעולות הלוח", - "selectedShapeActions": "פעולות צורה שנבחרה", + "canvasActions": "פעולות קנבאס", + "selectedShapeActions": "פעולות על הצורות שנבחרו", "shapes": "צורות" }, "hints": { - "canvasPanning": "", - "linearElement": "הקלק בשביל לבחור נקודות מרובות, גרור בשביל קו בודד", + "canvasPanning": "כדי להזיז את הקנבס, החזק את גלגל העכבר לחוץ או את מקש הרווח לחוץ תוך כדי גרירה, או השתמש בכלי היד", + "linearElement": "לחץ להתחלת מספר נקודות, גרור לקו יחיד", "freeDraw": "לחץ וגרור, שחרר כשסיימת", "text": "טיפ: אפשר להוסיף טקסט על ידי לחיצה כפולה בכל מקום עם כלי הבחירה", - "text_selected": "לחץ לחיצה כפולה או אנטר לעריכת הנקודות", - "text_editing": "כדי לסיים את העריכה לחצו על מקש Escape או על Ctrl ומקש Enter (Cmd במחשבי אפל)", + "text_selected": "לחץ לחיצה כפולה או הקש על אנטר לעריכת הטקסט", + "text_editing": "כדי לסיים את העריכה לחץ על מקש Escape או על Ctrl (Cmd במחשבי אפל) ומקש Enter", "linearElementMulti": "הקלק על הנקודה האחרונה או הקש Escape או Enter לסיום", - "lockAngle": "אתה יכול להגביל זווית ע״י לחיצה על SHIFT", + "lockAngle": "ניתן להגביל את הזוויות על ידי החזקה של מקש ה- SHIFT", "resize": "ניתן להגביל פרופורציות על ידי לחיצה על SHIFT תוך כדי שינוי גודל,\nהחזק ALT בשביל לשנות גודל ביחס למרכז", - "resizeImage": "", + "resizeImage": "אתה יכול לשנות את הגודל בחופשיות על ידי החזקת מקש SHIFT,\nהחזק את מקש ALT כדי לבצע שינוי גודל מהמרכז", "rotate": "ניתן להגביל זוויות על ידי לחיצה על SHIFT תוך כדי סיבוב", - "lineEditor_info": "", - "lineEditor_pointSelected": "", - "lineEditor_nothingSelected": "", - "placeImage": "", - "publishLibrary": "פירסום ספריה אישית", - "bindTextToElement": "יש להקיש Enter כדי להוסיף טקסט", - "deepBoxSelect": "", - "eraserRevert": "", - "firefox_clipboard_write": "" + "lineEditor_info": "החזק Ctrl / Cmd ובצע לחיצה כפולה או לחץ Ctrl / Cmd + Enter לעריכת נקודות", + "lineEditor_pointSelected": "לחץ Delete למחיקת נקודה/ות,\nCtrl / Cmd + D לשכפול, או גרור להזזה", + "lineEditor_nothingSelected": "בחר נקודה כדי לערוך (החזק SHIFT לבחירת כמה),\nאו החזק Alt והקלק להוספת נקודות חדשות", + "placeImage": "הקלק להנחת התמונה, או הקלק וגרור להגדרת הגודל שלו ידנית", + "publishLibrary": "פרסם ספריה משלך", + "bindTextToElement": "הקש Enter כדי להוספת טקסט", + "deepBoxSelect": "החזק Ctrl / Cmd לבחירה עמוקה ולמניעת גרירה", + "eraserRevert": "החזק Alt להחזרת רכיבים מסומנים למחיקה", + "firefox_clipboard_write": "יכולות זה ניתנת להפעלה על ידי שינוי הדגל של \"dom.events.asyncClipboard.clipboardItem\" למצב \"true\". כדי לשנות את הדגל בדפדפן Firefox, בקר בעמוד ״about:config״." }, "canvasError": { - "cannotShowPreview": "לא הצלחנו להציג את התצוגה המקדימה", + "cannotShowPreview": "לא ניתן להראות תצוגה מקדימה", "canvasTooBig": "הקנבס עלול להיות גדול מדי.", - "canvasTooBigTip": "טיפ: נסה להזיז את האלמנטים הרחוקים ביותר מעט קרוב יותר יחד." + "canvasTooBigTip": "טיפ: נסה להזיז את הרכיבים הרחוקים ביותר מעט קרוב יותר האחד לשני." }, "errorSplash": { "headingMain_pre": "אירעה שגיאה. נסה ", "headingMain_button": "טוען את העמוד מחדש.", "clearCanvasMessage": "אם טעינה מחדש לא עובדת, נסה ", - "clearCanvasMessage_button": "מנקה את הלוח.", - "clearCanvasCaveat": " זה יביא לאובדן עבודה ", - "trackedToSentry_pre": "שגיאה עם מזהה ", + "clearCanvasMessage_button": "מנקה את הקנבאס.", + "clearCanvasCaveat": " זה יגרום לאובדן העבודה ", + "trackedToSentry_pre": "השגיאה עם מזהה ", "trackedToSentry_post": " נמצאה במערכת שלנו.", - "openIssueMessage_pre": "נזהרנו מאוד שלא לכלול מידע שלך בשגיאה. אם המידע איננו אישי, בבקשה עקוב אחר ", + "openIssueMessage_pre": "נזהרנו מאוד שלא לכלול מידע מהקנבאס שלך בשגיאה. אם המידע בקנבאס אינו אישי, שקול לבצע מעקב אחר הטיפול שלנו ", "openIssueMessage_button": "מעקב באגים.", - "openIssueMessage_post": " בבקשה כלול את המידע למטה באמצעות העתקה והדבקה בנושא ב GitHub.", - "sceneContent": "תוכן הלוח:" + "openIssueMessage_post": " בבקשה כלול את המידע מטה באמצעות העתקתה שלו, והדבקה שלו ב- GitHub Issue.", + "sceneContent": "תוכן הקנבאס:" }, "roomDialog": { - "desc_intro": "אתה יכול להזמין אנשים ללוח הנוכחי שלך בכדי לשתף פעולה.", + "desc_intro": "אתה יכול להזמין אנשים לקנבאס הנוכחי שלך לעבודה משותפת.", "desc_privacy": "אל דאגה, השיתוף מוצפן מקצה לקצה, כך שכל מה שתצייר ישאר פרטי. אפילו השרתים שלנו לא יוכלו לראות את מה שאתה ממציא.", "button_startSession": "התחל שיתוף", "button_stopSession": "הפסק שיתוף", - "desc_inProgressIntro": "שיתוף חי כרגע בפעולה.", + "desc_inProgressIntro": "שיתוף חי פעיל כרגע.", "desc_shareLink": "שתף את הקישור עם כל מי שאתה מעוניין לעבוד אתו:", - "desc_exitSession": "עצירת השיתוף תנתק אותך מהחדר, אבל עדיין תוכל להמשיך לעבוד על הלוח, מקומית. שים לב שזה לא ישפיע על אנשים אחרים, והם עדיין יוכלו לשתף פעולה עם הגירסה שלהם.", - "shareTitle": "הצטרף לסשן שיתוף בזמן אמת של Excalidraw" + "desc_exitSession": "עצירת השיתוף תנתק אותך מהחדר, אבל עדיין תוכל להמשיך לעבוד על הקנבאס, מקומית. שים לב שזה לא ישפיע על אנשים אחרים, והם עדיין יוכלו לבצע שיתוף עם הגרסה שלהם.", + "shareTitle": "הצטרף לשיתוף לעבודה משותפת חיה, בזמן אמת, על גבי Excalidraw" }, "errorDialog": { "title": "שגיאה" }, "exportDialog": { "disk_title": "שמור לכונן", - "disk_details": "ייצוא מידע הסצינה לקובץ אותו ניתן יהיה לייבא בהמשך.", + "disk_details": "ייצא מידע של הקנבאס לקובץ שתוכל לייבא אחר כך.", "disk_button": "שמירה לקובץ", - "link_title": "העתקת קישור לשיתוף", + "link_title": "קבל קישור לשיתוף", "link_details": "ייצוא כקישור לקריאה בלבד.", - "link_button": "ייצוא כקישור", - "excalidrawplus_description": "שמור את המפה לסביבת העבודה שלך ב-Excalidraw+.", + "link_button": "ייצוא לקישור", + "excalidrawplus_description": "שמור את הקנבאס לסביבת העבודה שלך ב- +Excalidraw.", "excalidrawplus_button": "ייצוא", - "excalidrawplus_exportError": "הייצוא ל-Excalidraw+ לא הצליח לעת עתה..." + "excalidrawplus_exportError": "לא הצלחתי לייצא ל- +Excalidraw כרגע..." }, "helpDialog": { "blog": "קרא את הבלוג שלנו", @@ -301,30 +317,31 @@ "curvedLine": "קו מעוגל", "documentation": "תיעוד", "doubleClick": "לחיצה כפולה", - "drag": "לגרור", + "drag": "גרור", "editor": "עורך", - "editSelectedShape": "ערוך את הצורה הנבחרת (טקסט/חץ/קו)", + "editLineArrowPoints": "", + "editText": "", "github": "מצאת בעיה? דווח", "howto": "עקוב אחר המדריכים שלנו", "or": "או", "preventBinding": "למנוע נעיצת חיצים", "tools": "כלים", "shortcuts": "קיצורי מקלדת", - "textFinish": "סיים עריכה (טקסט)", - "textNewLine": "הוסף שורה חדשה (טקסט)", + "textFinish": "סיים עריכה (עורך טקסט)", + "textNewLine": "הוסף שורה חדשה (עורך טקסט)", "title": "עזרה", "view": "תצוגה", - "zoomToFit": "גלילה להצגת כל האלמנטים במסך", + "zoomToFit": "זום להתאמת כל האלמנטים למסך", "zoomToSelection": "התמקד בבחירה", "toggleElementLock": "נעילה/ביטול הנעילה של הרכיבים הנבחרים", - "movePageUpDown": "", - "movePageLeftRight": "" + "movePageUpDown": "זוז עמוד למעלה/למטה", + "movePageLeftRight": "זוז עמוד שמאלה/ימינה" }, "clearCanvasDialog": { "title": "ניקוי הקנבס" }, "publishDialog": { - "title": "פרסום ספריה", + "title": "פרסם ספריה", "itemName": "שם הפריט", "authorName": "שם היוצר", "githubUsername": "שם המשתמש שלך ב-GitHub", @@ -333,11 +350,11 @@ "libraryDesc": "תיאור הספריה", "website": "אתר", "placeholder": { - "authorName": "שם או שם משתמש", + "authorName": "שמך או שם המשתמש שלך", "libraryName": "תנו שם לספריה", "libraryDesc": "תיאור של הספריה שלך כדי לסייע למשתמשים להבין את השימוש בה", - "githubHandle": "", - "twitterHandle": "", + "githubHandle": "כינוי GitHub (לא חובה), כדי שתוכל לערוך את הספרית לאחר שנשלחה לבדיקה", + "twitterHandle": "שם משתמש טוויטר (לא חובה), כדי שנדע למי לתת קרדיט כשאנחנו מפרסמים בטוויטר", "website": "קישור לאתר הפרטי שלך או לכל מקום אחר (אופציונאלי)" }, "errors": { @@ -345,44 +362,44 @@ "website": "הזינו כתובת URL תקינה" }, "noteDescription": { - "pre": "להציע את הספריה שלך להיות כלולה ב", - "link": "מאגר הספריה הציבורי", - "post": "כך שאחרים יוכלו לעשות שימוש בציורים שלהם." + "pre": "הגש את הספריה שלך להכללתה ב ", + "link": "מאגר הספריה הציבורית", + "post": "לשימושם של אנשים אחרים בציורים שלהם." }, "noteGuidelines": { - "pre": "הספריה צריכה לקבל אישור ידני. אנא קרא את ", + "pre": "הספריה צריכה לקבל אישור ידני קודם לכן. אנא קרא את ", "link": "הנחיות", - "post": "" + "post": " לפני השליחה. אתה תצטרך לחשבון GitHub כדי לתקשר ולבצע שינויים אם תתבקש, אבל זה לא דרישה הכרחית." }, "noteLicense": { - "pre": "", + "pre": "על ידי שליחה, אתה מסכים שהסיפריה תפורסם תחת ה- ", "link": "רישיון MIT, ", - "post": "שאומר בקצרה שכל אחד יכול לעשות בהם שימוש ללא מגבלות." + "post": "שאומר בקצרה, שכל אחד יכול לעשות בהם שימוש ללא מגבלות." }, - "noteItems": "", - "atleastOneLibItem": "", - "republishWarning": "" + "noteItems": "לכל פריט בסיפריה חייב להיות שם כדי שאפשר יהיה לסנן. הפריטי סיפריה הבאים יהיו כלולים:", + "atleastOneLibItem": "אנא בחר לפחות פריט אחד מספריה כדי להתחיל", + "republishWarning": "הערה: חלק מהפריטים שבחרת מסומנים ככאלו שכבר פורסמו/נשלחו. אתה צריך לשלוח פריטים מחדש כאשר אתה מעדכן ספריה או הגשה קיימים." }, "publishSuccessDialog": { - "title": "הספריה נשלחה", + "title": "הספריה הוגשה", "content": "תודה {{authorName}}. הספריה שלך נשלחה לבחינה. תוכל לעקוב אחרי סטטוס הפרסום", "link": "כאן" }, "confirmDialog": { "resetLibrary": "איפוס ספריה", - "removeItemsFromLib": "להסיר את הפריטים הנבחרים מהספריה" + "removeItemsFromLib": "הסר את הפריטים הנבחרים מהספריה" }, "encrypted": { - "tooltip": "הרישומים שלך מוצפנים מקצה לקצה כך שהשרתים של Excalidraw לא יראו אותם לעולם.", + "tooltip": "הציורים שלך מוצפנים מקצה לקצה כך שהשרתים של Excalidraw לא יראו אותם לעולם.", "link": "פוסט בבלוג על הצפנה מקצה לקצב ב-Excalidraw" }, "stats": { "angle": "זווית", - "element": "אלמנט", - "elements": "אלמנטים", + "element": "רכיב", + "elements": "רכיבים", "height": "גובה", "scene": "תצוגה", - "selected": "נבחר/ים", + "selected": "נבחר", "storage": "אחסון", "title": "סטטיסטיקות לחנונים", "total": "סה״כ", @@ -393,14 +410,14 @@ }, "toast": { "addedToLibrary": "נוסף לספריה", - "copyStyles": "העתק סגנונות.", - "copyToClipboard": "הועתק אל הלוח.", + "copyStyles": "סגנונות הועתקו.", + "copyToClipboard": "הועתק ללוח.", "copyToClipboardAsPng": "{{exportSelection}} הועתקה ללוח כ-PNG\n({{exportColorScheme}})", "fileSaved": "קובץ נשמר.", "fileSavedToFilename": "נשמר לקובץ {filename}", - "canvas": "משטח ציור", + "canvas": "קנבאס", "selection": "בחירה", - "pasteAsSingleElement": "" + "pasteAsSingleElement": "השתמש ב- {{shortcut}} כדי להדביק כפריט יחיד,\nאו הדבק לתוך עורך טקסט קיים" }, "colors": { "ffffff": "לבן", @@ -443,23 +460,23 @@ "364fc7": "כחול כהה 9", "1864ab": "כחול 9", "0b7285": "טורקיז 9", - "087f5b": "ירקרק 9", + "087f5b": "ירוק-כחול 9", "2b8a3e": "ירוק 9", "5c940d": "ליים 9", - "e67700": "ירוק 9", + "e67700": "צהוב 9", "d9480f": "כתום 9" }, "welcomeScreen": { "app": { - "center_heading": "", - "center_heading_plus": "", - "menuHint": "" + "center_heading": "כל המידע שלח נשמר מקומית בדפדפן.", + "center_heading_plus": "אתה רוצה ללכת אל Excalidraw+ במקום?", + "menuHint": "ייצוא, העדפות, שפות, ..." }, "defaults": { - "menuHint": "", - "center_heading": "", - "toolbarHint": "", - "helpHint": "" + "menuHint": "ייצוא, העדפות, ועוד...", + "center_heading": "איורים. נעשים. פשוטים.", + "toolbarHint": "בחר כלי & והתחל לצייר!", + "helpHint": "קיצורים & עזרה" } } } diff --git a/src/locales/hi-IN.json b/src/locales/hi-IN.json index 9e3a14d64..77d6dae2d 100644 --- a/src/locales/hi-IN.json +++ b/src/locales/hi-IN.json @@ -110,6 +110,7 @@ "increaseFontSize": "फ़ॉन्ट आकार बढ़ाएँ", "unbindText": "", "bindText": "लेखन को कोश से जोड़े", + "createContainerFromText": "मूलपाठ कंटेनर में मोड के दिखाए", "link": { "edit": "", "create": "", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "कॉलेब सर्वर से कनेक्शन नहीं हो पा रहा. कृपया पृष्ठ को पुनः लाने का प्रयास करे.", "importLibraryError": "संग्रह प्रतिष्ठापित नहीं किया जा सका", "collabSaveFailed": "किसी कारण वश अंदरूनी डेटाबेस में सहेजा नहीं जा सका। यदि समस्या बनी रहती है, तो किये काम को खोने न देने के लिये अपनी फ़ाइल को स्थानीय रूप से सहेजे।", - "collabSaveFailed_sizeExceeded": "लगता है कि पृष्ठ तल काफ़ी बड़ा है, इस्कारण अंदरूनी डेटाबेस में सहेजा नहीं जा सका। किये काम को खोने न देने के लिये अपनी फ़ाइल को स्थानीय रूप से सहेजे।" + "collabSaveFailed_sizeExceeded": "लगता है कि पृष्ठ तल काफ़ी बड़ा है, इस्कारण अंदरूनी डेटाबेस में सहेजा नहीं जा सका। किये काम को खोने न देने के लिये अपनी फ़ाइल को स्थानीय रूप से सहेजे।", + "brave_measure_text_error": { + "start": "ऐसा लगता है कि आप ब्रेव ब्राउज़र का उपयोग कर रहे है, उसके साथ", + "aggressive_block_fingerprint": "उग्रतापूर्वक उंगलियों के निशान रोकने की", + "setting_enabled": "सेटिंग सक्रिय की गई है।", + "break": "इसके परिणाम स्वरूम टूट सकता है यह", + "text_elements": "मूल पाठ अवयव टूट सकते हैं", + "in_your_drawings": "आपके चित्र में उपस्थित", + "strongly_recommend": "हमारा शशक्त अनुरोध इस सेटिंग्स को अक्षम करने का है. आप", + "steps": "इन दिए हुए स्टेप्स को अनुकरीत करके देख सकते है कि", + "how": "ये कैसे करे", + "disable_setting": " यदि इन सेटिंग्स को निष्क्रिय करने पर भी, पाठ्य दिखना ठीक न हो तो", + "issue": "समस्या", + "write": "हमारे \"GitHub\" पर, अथवा", + "discord": "\"Discord\" पर लिख सकते हैं." + } }, "toolBar": { "selection": "चयन", @@ -303,7 +319,8 @@ "doubleClick": "", "drag": "खींचें", "editor": "संपादक", - "editSelectedShape": "", + "editLineArrowPoints": "रेखा/तीर बिंदु सम्पादित करे", + "editText": "पाठ्य सम्पादित करे/ लेबल जोड़े", "github": "मुद्दा मिला? प्रस्तुत करें", "howto": "हमारे गाइड का पालन करें", "or": "या", diff --git a/src/locales/hu-HU.json b/src/locales/hu-HU.json index a3cbd852c..d514520ed 100644 --- a/src/locales/hu-HU.json +++ b/src/locales/hu-HU.json @@ -110,6 +110,7 @@ "increaseFontSize": "Betűméret növelése", "unbindText": "Szövegkötés feloldása", "bindText": "", + "createContainerFromText": "", "link": { "edit": "Hivatkozás szerkesztése", "create": "Hivatkozás létrehozása", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Kijelölés", @@ -303,7 +319,8 @@ "doubleClick": "dupla kattintás", "drag": "vonszolás", "editor": "Szerkesztő", - "editSelectedShape": "Kijelölt alakzat szerkesztése (szöveg/nyíl/vonal)", + "editLineArrowPoints": "", + "editText": "", "github": "Hibát találtál? Küld be", "howto": "Kövesd az útmutatóinkat", "or": "vagy", diff --git a/src/locales/id-ID.json b/src/locales/id-ID.json index cd722c6a3..01b510fcd 100644 --- a/src/locales/id-ID.json +++ b/src/locales/id-ID.json @@ -110,6 +110,7 @@ "increaseFontSize": "Besarkan ukuran font", "unbindText": "Lepas teks", "bindText": "Kunci teks ke kontainer", + "createContainerFromText": "", "link": { "edit": "Edit tautan", "create": "Buat tautan", @@ -193,7 +194,7 @@ "resetLibrary": "Ini akan menghapus pustaka Anda. Anda yakin?", "removeItemsFromsLibrary": "Hapus {{count}} item dari pustaka?", "invalidEncryptionKey": "Sandi enkripsi harus 22 karakter. Kolaborasi langsung dinonaktifkan.", - "collabOfflineWarning": "" + "collabOfflineWarning": "Tidak ada koneksi internet.\nPerubahan tidak akan disimpan!" }, "errors": { "unsupportedFileType": "Tipe file tidak didukung.", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Tidak dapat terhubung ke server kolab. Muat ulang laman dan coba lagi.", "importLibraryError": "Tidak dapat memuat pustaka", "collabSaveFailed": "Tidak dapat menyimpan ke dalam basis data server. Jika masih berlanjut, Anda sebaiknya simpan berkas Anda secara lokal untuk memastikan pekerjaan Anda tidak hilang.", - "collabSaveFailed_sizeExceeded": "Tidak dapat menyimpan ke dalam basis data server, tampaknya ukuran kanvas terlalu besar. Anda sebaiknya simpan berkas Anda secara lokal untuk memastikan pekerjaan Anda tidak hilang." + "collabSaveFailed_sizeExceeded": "Tidak dapat menyimpan ke dalam basis data server, tampaknya ukuran kanvas terlalu besar. Anda sebaiknya simpan berkas Anda secara lokal untuk memastikan pekerjaan Anda tidak hilang.", + "brave_measure_text_error": { + "start": "Sepertinya kamu menggunakan browser Brave dengan", + "aggressive_block_fingerprint": "", + "setting_enabled": "pengaturan diaktifkan", + "break": "", + "text_elements": "Elemen Teks", + "in_your_drawings": "dalam gambar anda", + "strongly_recommend": "Kami sangat menyarankan untuk mematikan pengaturan ini. Kamu dapat mengikuti", + "steps": "langkah-langkah ini", + "how": "dalam bagaimana melakukan itu", + "disable_setting": " Jika pengaturan ini dimatikan tidak mengatasi masalah tampilan dari elemen teks, silahkan buka", + "issue": "isu", + "write": "di GitHub kami, atau tulis kami di", + "discord": "Discord" + } }, "toolBar": { "selection": "Pilihan", @@ -303,7 +319,8 @@ "doubleClick": "klik-ganda", "drag": "seret", "editor": "Editor", - "editSelectedShape": "Edit bentuk yang dipilih (teks/panah/garis)", + "editLineArrowPoints": "", + "editText": "", "github": "Menemukan masalah? Kirimkan", "howto": "Ikuti panduan kami", "or": "atau", diff --git a/src/locales/it-IT.json b/src/locales/it-IT.json index 3c6cf93a8..8380fd8e5 100644 --- a/src/locales/it-IT.json +++ b/src/locales/it-IT.json @@ -110,6 +110,7 @@ "increaseFontSize": "Aumenta la dimensione dei caratteri", "unbindText": "Scollega testo", "bindText": "Associa il testo al container", + "createContainerFromText": "", "link": { "edit": "Modifica link", "create": "Crea link", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Impossibile connettersi al server di collab. Ricarica la pagina e riprova.", "importLibraryError": "Impossibile caricare la libreria", "collabSaveFailed": "Impossibile salvare nel database di backend. Se i problemi persistono, dovresti salvare il tuo file localmente per assicurarti di non perdere il tuo lavoro.", - "collabSaveFailed_sizeExceeded": "Impossibile salvare nel database di backend, la tela sembra essere troppo grande. Dovresti salvare il file localmente per assicurarti di non perdere il tuo lavoro." + "collabSaveFailed_sizeExceeded": "Impossibile salvare nel database di backend, la tela sembra essere troppo grande. Dovresti salvare il file localmente per assicurarti di non perdere il tuo lavoro.", + "brave_measure_text_error": { + "start": "Sembra che tu stia usando il browser Brave con il", + "aggressive_block_fingerprint": "Blocco Aggressivamente Impronte Digitali", + "setting_enabled": "impostazioni abilitate", + "break": "Questo potrebbe portare a rompere gli", + "text_elements": "Elementi Di Testo", + "in_your_drawings": "nei tuoi disegni", + "strongly_recommend": "Si consiglia vivamente di disabilitare questa impostazione. È possibile seguire", + "steps": "questi passaggi", + "how": "su come fare", + "disable_setting": " Se la disabilitazione di questa impostazione non corregge la visualizzazione degli elementi di testo, apri un", + "issue": "problema", + "write": "sul nostro GitHub, o scrivici su", + "discord": "Discord" + } }, "toolBar": { "selection": "Selezione", @@ -303,7 +319,8 @@ "doubleClick": "doppio-click", "drag": "trascina", "editor": "Editor", - "editSelectedShape": "Modifica la forma selezionata (testo/freccia/linea)", + "editLineArrowPoints": "", + "editText": "Modifica testo / aggiungi etichetta", "github": "Trovato un problema? Segnalalo", "howto": "Segui le nostre guide", "or": "oppure", diff --git a/src/locales/ja-JP.json b/src/locales/ja-JP.json index 4f7a76afe..53333aea3 100644 --- a/src/locales/ja-JP.json +++ b/src/locales/ja-JP.json @@ -110,6 +110,7 @@ "increaseFontSize": "フォントサイズを拡大", "unbindText": "テキストのバインド解除", "bindText": "テキストをコンテナにバインド", + "createContainerFromText": "", "link": { "edit": "リンクを編集", "create": "リンクを作成", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "コラボレーションサーバに接続できませんでした。ページを再読み込みして、もう一度お試しください。", "importLibraryError": "ライブラリを読み込めませんでした。", "collabSaveFailed": "バックエンドデータベースに保存できませんでした。問題が解決しない場合は、作業を失わないようにローカルにファイルを保存してください。", - "collabSaveFailed_sizeExceeded": "キャンバスが大きすぎるため、バックエンドデータベースに保存できませんでした。問題が解決しない場合は、作業を失わないようにローカルにファイルを保存してください。" + "collabSaveFailed_sizeExceeded": "キャンバスが大きすぎるため、バックエンドデータベースに保存できませんでした。問題が解決しない場合は、作業を失わないようにローカルにファイルを保存してください。", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "設定が有効化されました", + "break": "", + "text_elements": "テキスト要素", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "Discord" + } }, "toolBar": { "selection": "選択", @@ -303,7 +319,8 @@ "doubleClick": "ダブルクリック", "drag": "ドラッグ", "editor": "エディタ", - "editSelectedShape": "選択した図形の編集 (テキスト/矢印/線)", + "editLineArrowPoints": "", + "editText": "テキストの編集 / ラベルの追加", "github": "不具合報告はこちら", "howto": "ヘルプ・マニュアル", "or": "または", diff --git a/src/locales/kab-KAB.json b/src/locales/kab-KAB.json index 3603e88c7..ba6a3de7e 100644 --- a/src/locales/kab-KAB.json +++ b/src/locales/kab-KAB.json @@ -110,6 +110,7 @@ "increaseFontSize": "Sali tiddi n tsefsit", "unbindText": "Serreḥ iweḍris", "bindText": "Arez aḍris s anagbar", + "createContainerFromText": "", "link": { "edit": "Ẓreg aseɣwen", "create": "Snulfu-d aseɣwen", @@ -193,7 +194,7 @@ "resetLibrary": "Ayagi ad isfeḍ tamkarḍit-inek•m. Tetḥeqqeḍ?", "removeItemsFromsLibrary": "Ad tekkseḍ {{count}} n uferdis (en) si temkarḍit?", "invalidEncryptionKey": "Tasarut n uwgelhen isefk ad tesɛu 22 n yiekkilen. Amɛiwen srid yensa.", - "collabOfflineWarning": "" + "collabOfflineWarning": "Ulac tuqqna n internet.\nIbedilen-ik ur ttwaklasen ara!" }, "errors": { "unsupportedFileType": "Anaw n ufaylu ur yettwasefrak ara.", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Ulamek tuqqna s aqeddac n umyalel. Ma ulac uɣilif ales asali n usebter sakin eɛreḍ tikkelt-nniḍen.", "importLibraryError": "Ur d-ssalay ara tamkarḍit", "collabSaveFailed": "Ulamek asekles deg uzadur n yisefka deg ugilal. Ma ikemmel wugur, isefk ad teskelseḍ afaylu s wudem adigan akken ad tetḥeqqeḍ ur tesruḥuyeḍ ara amahil-inek•inem.", - "collabSaveFailed_sizeExceeded": "Ulamek asekles deg uzadur n yisefka deg ugilal, taɣzut n usuneɣ tettban-d temqer aṭas. Isefk ad teskelseḍ afaylu s wudem adigan akken ad tetḥeqqeḍ ur tesruḥuyeḍ ara amahil-inek•inem." + "collabSaveFailed_sizeExceeded": "Ulamek asekles deg uzadur n yisefka deg ugilal, taɣzut n usuneɣ tettban-d temqer aṭas. Isefk ad teskelseḍ afaylu s wudem adigan akken ad tetḥeqqeḍ ur tesruḥuyeḍ ara amahil-inek•inem.", + "brave_measure_text_error": { + "start": "Ittban-d am wakken tsseqdaceḍ iminig Brave akked", + "aggressive_block_fingerprint": "", + "setting_enabled": "yermed", + "break": "Ayagi yezmer ad d-iseglu s truẓi n", + "text_elements": "Iferdisen iḍrisen", + "in_your_drawings": "deg wunuɣen-inek", + "strongly_recommend": "", + "steps": "isurifen-agi", + "how": "", + "disable_setting": "", + "issue": "", + "write": "di GitHub inek neɣ aru-yaɣ-d di", + "discord": "" + } }, "toolBar": { "selection": "Tafrayt", @@ -229,7 +245,7 @@ "shapes": "Talɣiwin" }, "hints": { - "canvasPanning": "", + "canvasPanning": "Akken ad tesmuttiḍ taɣzut n usuneɣ, ṭṭef ṛṛuda n umumed, neɣ seqdec afecku Afus", "linearElement": "Ssit akken ad tebduḍ aṭas n tenqiḍin, zuɣer i yiwen n yizirig", "freeDraw": "Ssit yerna zuɣer, serreḥ ticki tfukeḍ", "text": "Tixidest: tzemreḍ daɣen ad ternuḍ aḍris s usiti snat n tikkal anida tebɣiḍ s ufecku n tefrayt", @@ -240,7 +256,7 @@ "resize": "Tzemreḍ ad tḥettemeḍ assaɣ s tuṭṭfa n tqeffalt SHIFT mi ara tettbeddileḍ tiddi,\nma teṭṭfeḍ ALT abeddel n tiddi ad yili si tlemmast", "resizeImage": "Tzemreḍ ad talseḍ tiddi s tilelli s tuṭṭfa n SHIFT,\nṭṭef ALT akken ad talseḍ tiddi si tlemmast", "rotate": "Tzemreḍ ad tḥettemeḍ tiɣemmar s tuṭṭfa n SHIFT di tuzzya", - "lineEditor_info": "", + "lineEditor_info": "Ssed ɣef CtrlOrCmd yerna ssit snat n tikkal neɣ ssed ɣef CtrlOrCmd + Kcem akken ad tẓergeḍ tineqqiḍin", "lineEditor_pointSelected": "Ssed taqeffalt kkes akken ad tekkseḍ tanqiḍ (tinqiḍin),\nCtrlOrCmd+D akken ad tsiselgeḍ, neɣ zuɣer akken ad tesmuttiḍ", "lineEditor_nothingSelected": "Fren tanqiḍt akken ad tẓergeḍ (ṭṭef SHIFT akken ad tferneḍ aṭas),\nneɣ ṭṭef Alt akken ad ternuḍ tinqiḍin timaynutin", "placeImage": "Ssit akken ad tserseḍ tugna, neɣ ssit u zuɣer akken ad tesbaduḍ tiddi-ines s ufus", @@ -303,7 +319,8 @@ "doubleClick": "ssit snat n tikkal", "drag": "zuɣer", "editor": "Amaẓrag", - "editSelectedShape": "Ẓreg talɣa yettwafernen (aḍris/taneccabt/izirig)", + "editLineArrowPoints": "", + "editText": "", "github": "Tufiḍ-d ugur? Azen-aɣ-d", "howto": "Ḍfer imniren-nneɣ", "or": "neɣ", @@ -452,11 +469,11 @@ "welcomeScreen": { "app": { "center_heading": "", - "center_heading_plus": "", - "menuHint": "" + "center_heading_plus": "Tebɣiḍ ad tedduḍ ɣer Excalidraw+ deg umḍiq?", + "menuHint": "Asifeḍ, ismenyifen, tutlayin, ..." }, "defaults": { - "menuHint": "", + "menuHint": "Asifeḍ, ismenyifen, d wayen-nniḍen...", "center_heading": "", "toolbarHint": "", "helpHint": "" diff --git a/src/locales/kk-KZ.json b/src/locales/kk-KZ.json index ee1e44083..97a9063fa 100644 --- a/src/locales/kk-KZ.json +++ b/src/locales/kk-KZ.json @@ -110,6 +110,7 @@ "increaseFontSize": "", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { "edit": "", "create": "", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "", @@ -303,7 +319,8 @@ "doubleClick": "қос шерту", "drag": "апару", "editor": "Өңдеу", - "editSelectedShape": "Таңдалған пішінді өңдеу (мәтін/нұсқар/сызық)", + "editLineArrowPoints": "", + "editText": "", "github": "Қате таптыңыз ба? Жолдаңыз", "howto": "Біздің нұсқаулықтарды орындаңыз", "or": "немесе", diff --git a/src/locales/ko-KR.json b/src/locales/ko-KR.json index 9c02b3ea1..f170e4cbf 100644 --- a/src/locales/ko-KR.json +++ b/src/locales/ko-KR.json @@ -110,6 +110,7 @@ "increaseFontSize": "폰트 사이즈 키우기", "unbindText": "텍스트 분리", "bindText": "텍스트를 컨테이너에 결합", + "createContainerFromText": "텍스트를 컨테이너에 담기", "link": { "edit": "링크 수정하기", "create": "링크 만들기", @@ -193,7 +194,7 @@ "resetLibrary": "당신의 라이브러리를 초기화 합니다. 계속하시겠습니까?", "removeItemsFromsLibrary": "{{count}}개의 아이템을 라이브러리에서 삭제하시겠습니까?", "invalidEncryptionKey": "암호화 키는 반드시 22글자여야 합니다. 실시간 협업이 비활성화됩니다.", - "collabOfflineWarning": "" + "collabOfflineWarning": "인터넷에 연결되어 있지 않습니다.\n변경 사항들이 저장되지 않습니다!" }, "errors": { "unsupportedFileType": "지원하지 않는 파일 형식 입니다.", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "협업 서버에 접속하는데 실패했습니다. 페이지를 새로고침하고 다시 시도해보세요.", "importLibraryError": "라이브러리를 불러오지 못했습니다.", "collabSaveFailed": "데이터베이스에 저장하지 못했습니다. 문제가 계속 된다면, 작업 내용을 잃지 않도록 로컬 저장소에 저장해 주세요.", - "collabSaveFailed_sizeExceeded": "데이터베이스에 저장하지 못했습니다. 캔버스가 너무 큰 거 같습니다. 문제가 계속 된다면, 작업 내용을 잃지 않도록 로컬 저장소에 저장해 주세요." + "collabSaveFailed_sizeExceeded": "데이터베이스에 저장하지 못했습니다. 캔버스가 너무 큰 거 같습니다. 문제가 계속 된다면, 작업 내용을 잃지 않도록 로컬 저장소에 저장해 주세요.", + "brave_measure_text_error": { + "start": "귀하께서는", + "aggressive_block_fingerprint": "강력한 지문 차단", + "setting_enabled": "설정이 활성화된 Brave browser를 사용하고 계신 것 같습니다", + "break": "이 기능으로 인해 화이트보드의", + "text_elements": "텍스트 요소들이", + "in_your_drawings": "손상될 수 있습니다", + "strongly_recommend": "해당 기능을 설정에서 비활성화하는 것을 강력히 권장 드립니다. 비활성화 방법에 대해서는", + "steps": "이 게시글을", + "how": "참고해주세요.", + "disable_setting": " 만약 이 설정을 껐음에도 텍스트 요소들이 올바르게 표시되지 않는다면, 저희", + "issue": "Github에 이슈를", + "write": "올려주시거나", + "discord": "Discord에 제보해주세요" + } }, "toolBar": { "selection": "선택", @@ -221,7 +237,7 @@ "penMode": "펜 모드 - 터치 방지", "link": "선택한 도형에 대해서 링크를 추가/업데이트", "eraser": "지우개", - "hand": "" + "hand": "손 (패닝 도구)" }, "headings": { "canvasActions": "캔버스 동작", @@ -229,7 +245,7 @@ "shapes": "모양" }, "hints": { - "canvasPanning": "", + "canvasPanning": "캔버스를 옮기려면 마우스 휠이나 스페이스바를 누르고 드래그하거나, 손 도구를 사용하기", "linearElement": "여러 점을 연결하려면 클릭하고, 직선을 그리려면 바로 드래그하세요.", "freeDraw": "클릭 후 드래그하세요. 완료되면 놓으세요.", "text": "팁: 선택 툴로 아무 곳이나 더블 클릭해 텍스트를 추가할 수도 있습니다.", @@ -248,7 +264,7 @@ "bindTextToElement": "Enter 키를 눌러서 텍스트 추가하기", "deepBoxSelect": "CtrlOrCmd 키를 눌러서 깊게 선택하고, 드래그하지 않도록 하기", "eraserRevert": "Alt를 눌러서 삭제하도록 지정된 요소를 되돌리기", - "firefox_clipboard_write": "" + "firefox_clipboard_write": "이 기능은 설정에서 \"dom.events.asyncClipboard.clipboardItem\" 플래그를 \"true\"로 설정하여 활성화할 수 있습니다. Firefox에서 브라우저 플래그를 수정하려면, \"about:config\" 페이지에 접속하세요." }, "canvasError": { "cannotShowPreview": "미리보기를 볼 수 없습니다", @@ -303,7 +319,8 @@ "doubleClick": "더블 클릭", "drag": "드래그", "editor": "에디터", - "editSelectedShape": "선택한 도형 편집하기(텍스트/화살표/라인)", + "editLineArrowPoints": "", + "editText": "", "github": "문제 제보하기", "howto": "가이드 참고하기", "or": "또는", @@ -451,14 +468,14 @@ }, "welcomeScreen": { "app": { - "center_heading": "당신의 모든 데이터는 브라우저에 저장되었습니다.", + "center_heading": "모든 데이터는 브라우저에 안전하게 저장됩니다.", "center_heading_plus": "대신 Excalidraw+로 이동하시겠습니까?", "menuHint": "내보내기, 설정, 언어, ..." }, "defaults": { - "menuHint": "내보내기, 설정, 더 보기...", - "center_heading": "", - "toolbarHint": "도구 선택 & 그리기 시작", + "menuHint": "내보내기, 설정, 등등...", + "center_heading": "간단하게 만드는 다이어그램.", + "toolbarHint": "도구를 선택하고, 그리세요!", "helpHint": "단축키 & 도움말" } } diff --git a/src/locales/ku-TR.json b/src/locales/ku-TR.json index 4a8ebc95c..76b5086e8 100644 --- a/src/locales/ku-TR.json +++ b/src/locales/ku-TR.json @@ -110,6 +110,7 @@ "increaseFontSize": "زایدکردنی قەبارەی فۆنت", "unbindText": "دەقەکە جیابکەرەوە", "bindText": "دەقەکە ببەستەوە بە کۆنتەینەرەکەوە", + "createContainerFromText": "", "link": { "edit": "دەستکاریکردنی بەستەر", "create": "دروستکردنی بەستەر", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "ناتوانێت پەیوەندی بکات بە سێرڤەری کۆلاب. تکایە لاپەڕەکە دووبارە باربکەوە و دووبارە هەوڵ بدەوە.", "importLibraryError": "نەیتوانی کتێبخانە بار بکات", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "دەستنیشانکردن", @@ -303,7 +319,8 @@ "doubleClick": "دوو گرتە", "drag": "راکێشان", "editor": "دەستکاریکەر", - "editSelectedShape": "دەستکاریکردنی شێوەی هەڵبژێردراو (دەق/تیر/هێڵ)", + "editLineArrowPoints": "", + "editText": "", "github": "کێشەیەکت دۆزیەوە؟ پێشکەشکردن", "howto": "شوێن ڕینماییەکانمان بکەوە", "or": "یان", diff --git a/src/locales/lt-LT.json b/src/locales/lt-LT.json index a8a8d6639..d80739f09 100644 --- a/src/locales/lt-LT.json +++ b/src/locales/lt-LT.json @@ -110,6 +110,7 @@ "increaseFontSize": "", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { "edit": "Redeguoti nuorodą", "create": "Sukurti nuorodą", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Nepavyko prisijungti prie serverio bendradarbiavimui. Perkrauk puslapį ir pabandyk prisijungti dar kartą.", "importLibraryError": "Nepavyko įkelti bibliotekos", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Žymėjimas", @@ -303,7 +319,8 @@ "doubleClick": "dvigubas paspaudimas", "drag": "vilkti", "editor": "Redaktorius", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "Radai klaidą? Pateik", "howto": "Vadovaukis mūsų gidu", "or": "arba", diff --git a/src/locales/lv-LV.json b/src/locales/lv-LV.json index ea3180149..4a311f7cd 100644 --- a/src/locales/lv-LV.json +++ b/src/locales/lv-LV.json @@ -110,6 +110,7 @@ "increaseFontSize": "Palielināt fonta izmēru", "unbindText": "Atdalīt tekstu", "bindText": "Piesaistīt tekstu figūrai", + "createContainerFromText": "", "link": { "edit": "Rediģēt saiti", "create": "Izveidot saiti", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Nevarēja savienoties ar sadarbošanās serveri. Lūdzu, pārlādējiet lapu un mēģiniet vēlreiz.", "importLibraryError": "Nevarēja ielādēt bibliotēku", "collabSaveFailed": "Darbs nav saglabāts datubāzē. Ja problēma turpinās, saglabājiet datni lokālajā krātuvē, lai nodrošinātos pret darba pazaudēšanu.", - "collabSaveFailed_sizeExceeded": "Darbs nav saglabāts datubāzē, šķiet, ka tāfele ir pārāk liela. Saglabājiet datni lokālajā krātuvē, lai nodrošinātos pret darba pazaudēšanu." + "collabSaveFailed_sizeExceeded": "Darbs nav saglabāts datubāzē, šķiet, ka tāfele ir pārāk liela. Saglabājiet datni lokālajā krātuvē, lai nodrošinātos pret darba pazaudēšanu.", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Atlase", @@ -303,7 +319,8 @@ "doubleClick": "dubultklikšķis", "drag": "vilkt", "editor": "Redaktors", - "editSelectedShape": "Rediģēt atlasīto figūru (tekstu/bultu/līniju)", + "editLineArrowPoints": "", + "editText": "", "github": "Sastapāt kļūdu? Ziņot", "howto": "Sekojiet mūsu instrukcijām", "or": "vai", diff --git a/src/locales/mr-IN.json b/src/locales/mr-IN.json index e67fc3159..4f58009c9 100644 --- a/src/locales/mr-IN.json +++ b/src/locales/mr-IN.json @@ -110,6 +110,7 @@ "increaseFontSize": "अक्षर आकार मोठा करा", "unbindText": "लेखन संबंध संपवा", "bindText": "शब्द समूह ला पात्रात घ्या", + "createContainerFromText": "मजकूर कंटेनर मधे मोडून दाखवा", "link": { "edit": "दुवा संपादन", "create": "दुवा तयार करा", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "कॉलेब-सर्वर हे पोहोचत नाही आहे. पान परत लोड करायचा प्रयत्न करावे.", "importLibraryError": "संग्रह प्रतिस्थापित नाही करता आला", "collabSaveFailed": "काही कारणा निमित्त आतल्या डेटाबेसमध्ये जतन करू शकत नाही। समस्या तशिस राहिल्यास, तुम्ही तुमचे काम गमावणार नाही याची खात्री करण्यासाठी तुम्ही तुमची फाइल स्थानिक जतन करावी.", - "collabSaveFailed_sizeExceeded": "लगता है कि पृष्ठ तल काफ़ी बड़ा है, इस्कारण अंदरूनी डेटाबेस में सहेजा नहीं जा सका। किये काम को खोने न देने के लिये अपनी फ़ाइल को स्थानीय रूप से सहेजे।\n\nबॅकएंड डेटाबेसमध्ये जतन करू शकत नाही, कॅनव्हास खूप मोठा असल्याचे दिसते. तुम्ही तुमचे काम गमावणार नाही याची खात्री करण्यासाठी तुम्ही फाइल स्थानिक पातळीवर जतन करावी." + "collabSaveFailed_sizeExceeded": "लगता है कि पृष्ठ तल काफ़ी बड़ा है, इस्कारण अंदरूनी डेटाबेस में सहेजा नहीं जा सका। किये काम को खोने न देने के लिये अपनी फ़ाइल को स्थानीय रूप से सहेजे।\n\nबॅकएंड डेटाबेसमध्ये जतन करू शकत नाही, कॅनव्हास खूप मोठा असल्याचे दिसते. तुम्ही तुमचे काम गमावणार नाही याची खात्री करण्यासाठी तुम्ही फाइल स्थानिक पातळीवर जतन करावी.", + "brave_measure_text_error": { + "start": "असं वाटते की तुम्हीं \"Brave\" \"Browser\" वापरत आहात, त्या बरोबार", + "aggressive_block_fingerprint": "बोटांचे ठसे उग्रतेने थाम्बवाचे", + "setting_enabled": "सेटिंग्स सक्रिय केले आहेत", + "break": "ह्या कारणानिं", + "text_elements": "पाठ अवयव तुटु शकतात", + "in_your_drawings": "तुमच्या चित्रिकराणतले", + "strongly_recommend": "आमचा ज़ोरदार सल्ला असा कि सेटिंग्स निष्क्रिय करावे. तुम्हीं", + "steps": "ह्या स्टेप्स", + "how": "घेउ शकतात", + "disable_setting": " जर सेटिंग्स निष्क्रिय करून पाठ्य दिसणे ठीक नसेल होत तर", + "issue": "मुद्दा", + "write": "आमच्या Github वर, किव्हा आम्हाला", + "discord": "\"Discord\" वर लिहां" + } }, "toolBar": { "selection": "निवड", @@ -303,7 +319,8 @@ "doubleClick": "दुहेरी क्लिक", "drag": "ओढा", "editor": "संपादक", - "editSelectedShape": "निवडलेला प्रकार संपादित करा (मजकूर/बाण/रेघ)", + "editLineArrowPoints": "रेघ/तीर बिंदु सम्पादित करा", + "editText": "पाठ्य सम्पादित करा/ लेबल जोडा", "github": "समस्या मिळाली? प्रस्तुत करा", "howto": "आमच्या मार्गदर्शकाचे अनुसरण करा", "or": "किंवा", diff --git a/src/locales/my-MM.json b/src/locales/my-MM.json index e479d3702..efc874218 100644 --- a/src/locales/my-MM.json +++ b/src/locales/my-MM.json @@ -110,6 +110,7 @@ "increaseFontSize": "", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { "edit": "", "create": "", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "ရွေးချယ်", @@ -303,7 +319,8 @@ "doubleClick": "", "drag": "", "editor": "", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "", "howto": "", "or": "", diff --git a/src/locales/nb-NO.json b/src/locales/nb-NO.json index 653779a56..27e717d2a 100644 --- a/src/locales/nb-NO.json +++ b/src/locales/nb-NO.json @@ -110,6 +110,7 @@ "increaseFontSize": "Øk skriftstørrelse", "unbindText": "Avbind tekst", "bindText": "Bind tekst til beholderen", + "createContainerFromText": "La tekst flyte i en beholder", "link": { "edit": "Rediger lenke", "create": "Opprett lenke", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Kunne ikke koble til samarbeidsserveren. Vennligst oppdater siden og prøv på nytt.", "importLibraryError": "Kunne ikke laste bibliotek", "collabSaveFailed": "Kan ikke lagre i backend-databasen. Hvis problemer vedvarer, bør du lagre filen lokalt for å sikre at du ikke mister arbeidet.", - "collabSaveFailed_sizeExceeded": "Kunne ikke lagre til backend-databasen, lerretet ser ut til å være for stort. Du bør lagre filen lokalt for å sikre at du ikke mister arbeidet ditt." + "collabSaveFailed_sizeExceeded": "Kunne ikke lagre til backend-databasen, lerretet ser ut til å være for stort. Du bør lagre filen lokalt for å sikre at du ikke mister arbeidet ditt.", + "brave_measure_text_error": { + "start": "Ser ut som du bruker Brave nettleser med", + "aggressive_block_fingerprint": "Blokker fingeravtrykk aggressivt", + "setting_enabled": "innstilling aktivert", + "break": "Dette kan føre til at den bryter", + "text_elements": "Tekstelementer", + "in_your_drawings": "i tegningene dine", + "strongly_recommend": "Vi anbefaler på det sterkeste å deaktivere denne innstillingen. Du kan følge dette", + "steps": "disse trinnene", + "how": "om hvordan det skal gjøres", + "disable_setting": " Hvis deaktivering av denne innstillingen ikke fikser visningen av tekstelementer, kan du åpne en", + "issue": "sak", + "write": "på vår GitHub, eller skriv oss på", + "discord": "Discord" + } }, "toolBar": { "selection": "Velg", @@ -303,7 +319,8 @@ "doubleClick": "dobbeltklikk", "drag": "dra", "editor": "Redigeringsvisning", - "editSelectedShape": "Rediger valgt figur (tekst/pil/linje)", + "editLineArrowPoints": "Rediger linje/pilpunkter", + "editText": "Rediger tekst / legg til etikett", "github": "Funnet et problem? Send inn", "howto": "Følg våre veiledninger", "or": "eller", diff --git a/src/locales/nl-NL.json b/src/locales/nl-NL.json index 313c8dc47..7c2bb105b 100644 --- a/src/locales/nl-NL.json +++ b/src/locales/nl-NL.json @@ -110,6 +110,7 @@ "increaseFontSize": "Letters vergroten", "unbindText": "Ontkoppel tekst", "bindText": "Koppel tekst aan de container", + "createContainerFromText": "", "link": { "edit": "Wijzig link", "create": "Maak link", @@ -193,7 +194,7 @@ "resetLibrary": "Dit zal je bibliotheek wissen. Weet je het zeker?", "removeItemsFromsLibrary": "Verwijder {{count}} item(s) uit bibliotheek?", "invalidEncryptionKey": "Encryptiesleutel moet 22 tekens zijn. Live samenwerking is uitgeschakeld.", - "collabOfflineWarning": "" + "collabOfflineWarning": "Geen internetverbinding beschikbaar.\nJe wijzigingen worden niet opgeslagen!" }, "errors": { "unsupportedFileType": "Niet-ondersteund bestandstype.", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Kan geen verbinding maken met de collab server. Herlaad de pagina en probeer het opnieuw.", "importLibraryError": "Kon bibliotheek niet laden", "collabSaveFailed": "Kan niet opslaan in de backend database. Als de problemen blijven bestaan, moet u het bestand lokaal opslaan om ervoor te zorgen dat u uw werk niet verliest.", - "collabSaveFailed_sizeExceeded": "Kan de backend database niet opslaan, het canvas lijkt te groot te zijn. U moet het bestand lokaal opslaan om ervoor te zorgen dat u uw werk niet verliest." + "collabSaveFailed_sizeExceeded": "Kan de backend database niet opslaan, het canvas lijkt te groot te zijn. U moet het bestand lokaal opslaan om ervoor te zorgen dat u uw werk niet verliest.", + "brave_measure_text_error": { + "start": "Het ziet er uit dat u de Brave browser gebruikt met de", + "aggressive_block_fingerprint": "", + "setting_enabled": "instelling ingeschakeld", + "break": "Dit kan leiden tot het breken van de", + "text_elements": "Tekst Elementen", + "in_your_drawings": "in je tekeningen", + "strongly_recommend": "We raden u ten zeerste aan deze instelling uit te schakelen. U kunt dit volgen", + "steps": "deze stappen", + "how": "over hoe dit te doen", + "disable_setting": " Indien het uitschakelen van deze instelling de weergave van tekst elementen niet wijzigt, open dan een", + "issue": "probleem", + "write": "", + "discord": "Discord" + } }, "toolBar": { "selection": "Selectie", @@ -219,7 +235,7 @@ "library": "Bibliotheek", "lock": "Geselecteerde tool actief houden na tekenen", "penMode": "Pen modus - Blokkeer aanraken", - "link": "", + "link": "Link toevoegen / bijwerken voor een geselecteerde vorm", "eraser": "Gum", "hand": "" }, @@ -229,7 +245,7 @@ "shapes": "Vormen" }, "hints": { - "canvasPanning": "", + "canvasPanning": "Om de canvas te verplaatsen, houd muiswiel of spatiebalk ingedrukt tijdens slepen, of gebruik het handgereedschap", "linearElement": "Klik om meerdere punten te starten, sleep voor één lijn", "freeDraw": "Klik en sleep, laat los als je klaar bent", "text": "Tip: je kunt tekst toevoegen door ergens dubbel te klikken met de selectietool", @@ -245,7 +261,7 @@ "lineEditor_nothingSelected": "", "placeImage": "", "publishLibrary": "Publiceer je eigen bibliotheek", - "bindTextToElement": "", + "bindTextToElement": "Druk op enter om tekst toe te voegen", "deepBoxSelect": "", "eraserRevert": "", "firefox_clipboard_write": "" @@ -295,7 +311,7 @@ "helpDialog": { "blog": "Lees onze blog", "click": "klik", - "deepSelect": "", + "deepSelect": "Deep selecteer", "deepBoxSelect": "", "curvedArrow": "Gebogen pijl", "curvedLine": "Kromme lijn", @@ -303,7 +319,8 @@ "doubleClick": "dubbelklikken", "drag": "slepen", "editor": "Editor", - "editSelectedShape": "Bewerk geselecteerde vorm (tekst/pijl/lijn)", + "editLineArrowPoints": "", + "editText": "", "github": "Probleem gevonden? Verzenden", "howto": "Volg onze handleidingen", "or": "of", @@ -364,13 +381,13 @@ "republishWarning": "" }, "publishSuccessDialog": { - "title": "", + "title": "Bibliotheek ingediend", "content": "", "link": "Hier" }, "confirmDialog": { - "resetLibrary": "", - "removeItemsFromLib": "" + "resetLibrary": "Reset bibliotheek", + "removeItemsFromLib": "Verwijder geselecteerde items uit bibliotheek" }, "encrypted": { "tooltip": "Je tekeningen zijn beveiligd met end-to-end encryptie, dus Excalidraw's servers zullen nooit zien wat je tekent.", @@ -392,7 +409,7 @@ "width": "Breedte" }, "toast": { - "addedToLibrary": "", + "addedToLibrary": "Toegevoegd aan bibliotheek", "copyStyles": "Stijlen gekopieerd.", "copyToClipboard": "Gekopieerd naar het klembord.", "copyToClipboardAsPng": "{{exportSelection}} naar klembord gekopieerd als PNG\n({{exportColorScheme}})", @@ -456,10 +473,10 @@ "menuHint": "" }, "defaults": { - "menuHint": "", - "center_heading": "", - "toolbarHint": "", - "helpHint": "" + "menuHint": "Exporteren, voorkeuren en meer...", + "center_heading": "Diagrammen. Eenvoudig. Gemaakt.", + "toolbarHint": "Kies een tool & begin met tekenen!", + "helpHint": "Snelkoppelingen en hulp" } } } diff --git a/src/locales/nn-NO.json b/src/locales/nn-NO.json index 0311cc2fe..1733b84c4 100644 --- a/src/locales/nn-NO.json +++ b/src/locales/nn-NO.json @@ -110,6 +110,7 @@ "increaseFontSize": "Gjer skriftstorleik større", "unbindText": "Avbind tekst", "bindText": "", + "createContainerFromText": "", "link": { "edit": "Rediger lenke", "create": "Lag lenke", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Kunne ikkje kople til samarbeidsserveren. Ver vennleg å oppdatere inn sida og prøv på nytt.", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Vel", @@ -303,7 +319,8 @@ "doubleClick": "dobbelklikk", "drag": "drag", "editor": "Redigering", - "editSelectedShape": "Rediger valt form (tekst/pil/linje)", + "editLineArrowPoints": "", + "editText": "", "github": "Funne eit problem? Send inn", "howto": "Følg vegleiinga vår", "or": "eller", diff --git a/src/locales/oc-FR.json b/src/locales/oc-FR.json index 51a5b9018..a9ca70a84 100644 --- a/src/locales/oc-FR.json +++ b/src/locales/oc-FR.json @@ -110,6 +110,7 @@ "increaseFontSize": "Aumentar talha polissa", "unbindText": "Dessociar lo tèxte", "bindText": "Ligar lo tèxt al contenidor", + "createContainerFromText": "", "link": { "edit": "Modificar lo ligam", "create": "Crear un ligam", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Connexion impossibla al servidor collab. Mercés de recargar la pagina e tornar ensajar.", "importLibraryError": "Impossible de cargar la bibliotèca", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Seleccion", @@ -303,7 +319,8 @@ "doubleClick": "doble clic", "drag": "lisar", "editor": "Editor", - "editSelectedShape": "Modificar la fòrma seleccionada (tèxt/sageta/linha)", + "editLineArrowPoints": "", + "editText": "", "github": "Problèma trobat ? Senhalatz-lo", "howto": "Seguissètz nòstras guidas", "or": "o", diff --git a/src/locales/pa-IN.json b/src/locales/pa-IN.json index 3bf61d83a..31c11ceb8 100644 --- a/src/locales/pa-IN.json +++ b/src/locales/pa-IN.json @@ -110,6 +110,7 @@ "increaseFontSize": "ਫੌਂਟ ਦਾ ਅਕਾਰ ਵਧਾਓ", "unbindText": "", "bindText": "ਪਾਠ ਨੂੰ ਕੰਟੇਨਰ ਨਾਲ ਬੰਨ੍ਹੋ", + "createContainerFromText": "", "link": { "edit": "ਕੜੀ ਸੋਧੋ", "create": "ਕੜੀ ਬਣਾਓ", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "ਚੋਣਕਾਰ", @@ -303,7 +319,8 @@ "doubleClick": "ਡਬਲ-ਕਲਿੱਕ", "drag": "ਘਸੀਟੋ", "editor": "ਸੋਧਕ", - "editSelectedShape": "ਚੁਣਿਆ ਰੂਪ ਸੋਧੋ (ਪਾਠ/ਤੀਰ/ਲਾਈਨ)", + "editLineArrowPoints": "", + "editText": "", "github": "ਕੋਈ ਸਮੱਸਿਆ ਲੱਭੀ? ਜਮ੍ਹਾਂ ਕਰਵਾਓ", "howto": "ਸਾਡੀਆਂ ਗਾਈਡਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ", "or": "ਜਾਂ", diff --git a/src/locales/percentages.json b/src/locales/percentages.json index 29a0c1f2b..b28b6c259 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -1,52 +1,53 @@ { - "ar-SA": 92, - "bg-BG": 54, - "bn-BD": 59, - "ca-ES": 100, - "cs-CZ": 74, - "da-DK": 32, + "ar-SA": 89, + "bg-BG": 52, + "bn-BD": 57, + "ca-ES": 96, + "cs-CZ": 72, + "da-DK": 31, "de-DE": 100, - "el-GR": 99, + "el-GR": 98, "en": 100, - "es-ES": 100, - "eu-ES": 100, - "fa-IR": 95, - "fi-FI": 100, - "fr-FR": 100, + "es-ES": 99, + "eu-ES": 99, + "fa-IR": 91, + "fi-FI": 96, + "fr-FR": 99, "gl-ES": 99, - "he-IL": 89, - "hi-IN": 71, - "hu-HU": 88, - "id-ID": 99, - "it-IT": 100, - "ja-JP": 100, + "he-IL": 99, + "hi-IN": 73, + "hu-HU": 85, + "id-ID": 98, + "it-IT": 99, + "ja-JP": 97, "kab-KAB": 93, - "kk-KZ": 20, - "ko-KR": 98, - "ku-TR": 95, - "lt-LT": 63, - "lv-LV": 97, + "kk-KZ": 19, + "ko-KR": 99, + "ku-TR": 91, + "lt-LT": 61, + "lv-LV": 93, "mr-IN": 100, - "my-MM": 41, + "my-MM": 40, "nb-NO": 100, - "nl-NL": 90, - "nn-NO": 89, - "oc-FR": 98, - "pa-IN": 82, - "pl-PL": 84, - "pt-BR": 100, - "pt-PT": 100, + "nl-NL": 92, + "nn-NO": 86, + "oc-FR": 94, + "pa-IN": 79, + "pl-PL": 87, + "pt-BR": 96, + "pt-PT": 99, "ro-RO": 100, - "ru-RU": 100, + "ru-RU": 96, "si-LK": 8, - "sk-SK": 100, + "sk-SK": 99, "sl-SI": 100, - "sv-SE": 100, - "ta-IN": 94, - "tr-TR": 97, - "uk-UA": 96, - "vi-VN": 20, - "zh-CN": 100, + "sv-SE": 99, + "ta-IN": 90, + "th-TH": 39, + "tr-TR": 98, + "uk-UA": 93, + "vi-VN": 52, + "zh-CN": 99, "zh-HK": 25, "zh-TW": 100 } diff --git a/src/locales/pl-PL.json b/src/locales/pl-PL.json index 89a52b493..1abaa038f 100644 --- a/src/locales/pl-PL.json +++ b/src/locales/pl-PL.json @@ -1,7 +1,7 @@ { "labels": { "paste": "Wklej", - "pasteAsPlaintext": "", + "pasteAsPlaintext": "Wklej jako zwykły tekst", "pasteCharts": "Wklej wykresy", "selectAll": "Zaznacz wszystko", "multiSelect": "Dodaj element do zaznaczenia", @@ -72,7 +72,7 @@ "layers": "Warstwy", "actions": "Akcje", "language": "Język", - "liveCollaboration": "", + "liveCollaboration": "Współpraca w czasie rzeczywistym...", "duplicateSelection": "Powiel", "untitled": "Bez tytułu", "name": "Nazwa", @@ -96,8 +96,8 @@ "centerHorizontally": "Wyśrodkuj w poziomie", "distributeHorizontally": "Rozłóż poziomo", "distributeVertically": "Rozłóż pionowo", - "flipHorizontal": "Odbij w poziomie", - "flipVertical": "Odbij w pionie", + "flipHorizontal": "Odwróć w poziomie", + "flipVertical": "Odwróć w pionie", "viewMode": "Tryb widoku", "toggleExportColorScheme": "Przełącz schemat kolorów przy eksporcie", "share": "Udostępnij", @@ -106,46 +106,47 @@ "toggleTheme": "Przełącz motyw", "personalLib": "Biblioteka prywatna", "excalidrawLib": "Biblioteka Excalidraw", - "decreaseFontSize": "", - "increaseFontSize": "", + "decreaseFontSize": "Zmniejsz rozmiar czcionki", + "increaseFontSize": "Zwiększ rozmiar czcionki", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { - "edit": "", - "create": "", - "label": "" + "edit": "Edytuj łącze", + "create": "Utwórz łącze", + "label": "Łącze" }, "lineEditor": { "edit": "", "exit": "" }, "elementLock": { - "lock": "", - "unlock": "", - "lockAll": "", - "unlockAll": "" + "lock": "Zablokuj", + "unlock": "Odblokuj", + "lockAll": "Zablokuj wszystko", + "unlockAll": "Odblokuj wszystko" }, - "statusPublished": "", - "sidebarLock": "" + "statusPublished": "Opublikowano", + "sidebarLock": "Panel boczny zawsze otwarty" }, "library": { - "noItems": "", + "noItems": "Nie dodano jeszcze żadnych elementów...", "hint_emptyLibrary": "", - "hint_emptyPrivateLibrary": "" + "hint_emptyPrivateLibrary": "Wybierz element, aby dodać go tutaj." }, "buttons": { "clearReset": "Wyczyść dokument i zresetuj kolor dokumentu", "exportJSON": "Eksportuj do pliku", - "exportImage": "", - "export": "", + "exportImage": "Eksportuj obraz...", + "export": "Zapisz jako...", "exportToPng": "Zapisz jako PNG", "exportToSvg": "Zapisz jako SVG", "copyToClipboard": "Skopiuj do schowka", "copyPngToClipboard": "Skopiuj do schowka jako plik PNG", "scale": "Skala", - "save": "", + "save": "Zapisz do bieżącego pliku", "saveAs": "Zapisz jako", - "load": "", + "load": "Otwórz", "getShareableLink": "Udostępnij", "close": "Zamknij", "selectLanguage": "Wybierz język", @@ -179,11 +180,11 @@ "couldNotLoadInvalidFile": "Nie udało się otworzyć pliku. Wybrany plik jest nieprawidłowy.", "importBackendFailed": "Wystąpił błąd podczas importowania pliku.", "cannotExportEmptyCanvas": "Najpierw musisz coś narysować, aby zapisać dokument.", - "couldNotCopyToClipboard": "", + "couldNotCopyToClipboard": "Nie udało się skopiować do schowka.", "decryptFailed": "Nie udało się odszyfrować danych.", "uploadedSecurly": "By zapewnić Ci prywatność, udostępnianie projektu jest zabezpieczone szyfrowaniem end-to-end, co oznacza, że poza tobą i osobą z którą podzielisz się linkiem, nikt nie ma dostępu do tego co udostępniasz.", "loadSceneOverridePrompt": "Wczytanie zewnętrznego rysunku zastąpi istniejącą zawartość. Czy chcesz kontynuować?", - "collabStopOverridePrompt": "Zatrzymanie sesji nadpisze poprzedni, zapisany lokalnie rysunk. Jesteś pewien?\n\n(Jeśli chcesz zachować swój lokalny rysunek, po prostu zamknij zakładkę przeglądarki.)", + "collabStopOverridePrompt": "Zatrzymanie sesji nadpisze poprzedni, zapisany lokalnie rysunek. Czy jesteś pewien?\n\n(Jeśli chcesz zachować swój lokalny rysunek, po prostu zamknij zakładkę przeglądarki.)", "errorAddingToLibrary": "Nie udało się dodać elementu do biblioteki", "errorRemovingFromLibrary": "Nie udało się usunąć elementu z biblioteki", "confirmAddLibrary": "To doda {{numShapes}} kształtów do twojej biblioteki. Jesteś pewien?", @@ -193,7 +194,7 @@ "resetLibrary": "To wyczyści twoją bibliotekę. Jesteś pewien?", "removeItemsFromsLibrary": "Usunąć {{count}} element(ów) z biblioteki?", "invalidEncryptionKey": "Klucz szyfrowania musi składać się z 22 znaków. Współpraca na żywo jest wyłączona.", - "collabOfflineWarning": "" + "collabOfflineWarning": "Brak połączenia z Internetem.\nTwoje zmiany nie zostaną zapisane!" }, "errors": { "unsupportedFileType": "Nieobsługiwany typ pliku.", @@ -201,10 +202,25 @@ "fileTooBig": "Plik jest zbyt duży. Maksymalny dozwolony rozmiar to {{maxSize}}.", "svgImageInsertError": "Nie udało się wstawić obrazu SVG. Znacznik SVG wygląda na nieprawidłowy.", "invalidSVGString": "Nieprawidłowy SVG.", - "cannotResolveCollabServer": "", - "importLibraryError": "", - "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "cannotResolveCollabServer": "Nie można połączyć się z serwerem współpracy w czasie rzeczywistym. Proszę odświeżyć stronę i spróbować ponownie.", + "importLibraryError": "Wystąpił błąd w trakcie ładowania biblioteki", + "collabSaveFailed": "Nie udało się zapisać w bazie danych. Jeśli problemy nie ustąpią, zapisz plik lokalnie, aby nie utracić swojej pracy.", + "collabSaveFailed_sizeExceeded": "Nie udało się zapisać w bazie danych — dokument jest za duży. Zapisz plik lokalnie, aby nie utracić swojej pracy.", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "problem", + "write": "na naszym GitHubie lub napisz do nas na", + "discord": "Discord" + } }, "toolBar": { "selection": "Zaznaczenie", @@ -303,7 +319,8 @@ "doubleClick": "podwójne kliknięcie", "drag": "przeciągnij", "editor": "Edytor", - "editSelectedShape": "Edytuj wybrany kształt (tekst/strzałka/linia)", + "editLineArrowPoints": "", + "editText": "", "github": "Znalazłeś problem? Prześlij", "howto": "Skorzystaj z instrukcji", "or": "lub", @@ -317,7 +334,7 @@ "zoomToFit": "Powiększ, aby wyświetlić wszystkie elementy", "zoomToSelection": "Przybliż do zaznaczenia", "toggleElementLock": "", - "movePageUpDown": "", + "movePageUpDown": "Przesuń stronę w górę/w dół", "movePageLeftRight": "" }, "clearCanvasDialog": { diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index cb7f045de..d790c5db5 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -110,6 +110,7 @@ "increaseFontSize": "Aumentar o tamanho da fonte", "unbindText": "Desvincular texto", "bindText": "Vincular texto ao contêiner", + "createContainerFromText": "", "link": { "edit": "Editar link", "create": "Criar link", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Não foi possível conectar-se ao servidor colaborativo. Por favor, recarregue a página e tente novamente.", "importLibraryError": "Não foi possível carregar a biblioteca", "collabSaveFailed": "Não foi possível salvar no banco de dados do servidor. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho.", - "collabSaveFailed_sizeExceeded": "Não foi possível salvar no banco de dados do servidor, a tela parece ser muito grande. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho." + "collabSaveFailed_sizeExceeded": "Não foi possível salvar no banco de dados do servidor, a tela parece ser muito grande. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho.", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Seleção", @@ -303,7 +319,8 @@ "doubleClick": "clique duplo", "drag": "arrastar", "editor": "Editor", - "editSelectedShape": "Editar forma selecionada (texto/seta/linha)", + "editLineArrowPoints": "", + "editText": "", "github": "Encontrou algum problema? Nos informe", "howto": "Siga nossos guias", "or": "ou", diff --git a/src/locales/pt-PT.json b/src/locales/pt-PT.json index f713b22d3..7ce28f00f 100644 --- a/src/locales/pt-PT.json +++ b/src/locales/pt-PT.json @@ -110,6 +110,7 @@ "increaseFontSize": "Aumentar o tamanho do tipo de letra", "unbindText": "Desvincular texto", "bindText": "Ligar texto ao recipiente", + "createContainerFromText": "Envolver texto num recipiente", "link": { "edit": "Editar ligação", "create": "Criar ligação", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Não foi possível fazer a ligação ao servidor colaborativo. Por favor, volte a carregar a página e tente novamente.", "importLibraryError": "Não foi possível carregar a biblioteca", "collabSaveFailed": "Não foi possível guardar na base de dados de backend. Se os problemas persistirem, guarde o ficheiro localmente para garantir que não perde o seu trabalho.", - "collabSaveFailed_sizeExceeded": "Não foi possível guardar na base de dados de backend, o ecrã parece estar muito grande. Deve guardar o ficheiro localmente para garantir que não perde o seu trabalho." + "collabSaveFailed_sizeExceeded": "Não foi possível guardar na base de dados de backend, o ecrã parece estar muito grande. Deve guardar o ficheiro localmente para garantir que não perde o seu trabalho.", + "brave_measure_text_error": { + "start": "Parece que está a usar o navegador Brave com o", + "aggressive_block_fingerprint": "Bloqueio Agressivo via Impressão Digital", + "setting_enabled": "activo", + "break": "Isso pode desconfigurar os", + "text_elements": "Elementos de Texto", + "in_your_drawings": "nos seus desenhos", + "strongly_recommend": "Recomendamos fortemente a desactivação desta configuração. Pode seguir", + "steps": "os seguintes passos", + "how": "para saber como o fazer", + "disable_setting": " Se desactivar esta configuração não consertar a exibição de elementos de texto, por favor, abra um", + "issue": "problema", + "write": "no nosso GitHub ou então escreva-nos no", + "discord": "Discord" + } }, "toolBar": { "selection": "Seleção", @@ -303,7 +319,8 @@ "doubleClick": "clique duplo", "drag": "arrastar", "editor": "Editor", - "editSelectedShape": "Editar forma selecionada (texto/seta/linha)", + "editLineArrowPoints": "", + "editText": "", "github": "Encontrou algum problema? Informe-nos", "howto": "Siga os nossos guias", "or": "ou", diff --git a/src/locales/ro-RO.json b/src/locales/ro-RO.json index 8eda2385b..a0e3b5883 100644 --- a/src/locales/ro-RO.json +++ b/src/locales/ro-RO.json @@ -110,6 +110,7 @@ "increaseFontSize": "Mărește dimensiunea fontului", "unbindText": "Deconectare text", "bindText": "Legare text de container", + "createContainerFromText": "Încadrare text într-un container", "link": { "edit": "Editare URL", "create": "Creare URL", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Nu a putut fi realizată conexiunea la serverul de colaborare. Reîncarcă pagina și încearcă din nou.", "importLibraryError": "Biblioteca nu a putut fi încărcată", "collabSaveFailed": "Nu s-a putut salva în baza de date la nivel de server. Dacă problemele persistă, ar trebui să salvezi fișierul la nivel local pentru a te asigura că nu îți pierzi munca.", - "collabSaveFailed_sizeExceeded": "Nu s-a putut salva în baza de date la nivel de server, întrucât se pare că pânza este prea mare. Ar trebui să salvezi fișierul la nivel local pentru a te asigura că nu îți pierzi munca." + "collabSaveFailed_sizeExceeded": "Nu s-a putut salva în baza de date la nivel de server, întrucât se pare că pânza este prea mare. Ar trebui să salvezi fișierul la nivel local pentru a te asigura că nu îți pierzi munca.", + "brave_measure_text_error": { + "start": "Se pare că folosești navigatorul Brave cu", + "aggressive_block_fingerprint": "setarea „Blocați amprentarea” în modul strict", + "setting_enabled": "activată", + "break": "Acest lucru ar putea duce la întreruperea", + "text_elements": "elementelor de text", + "in_your_drawings": "din desenele tale", + "strongly_recommend": "Recomandăm insistent dezactivarea acestei setări. Poți urma", + "steps": "acești pași", + "how": "pentru efectuarea procedurii", + "disable_setting": " Dacă dezactivarea acestei setări nu remediază afișarea elementelor de text, deschide", + "issue": "un tichet cu probleme", + "write": "pe pagina noastră de GitHub sau scrie-ne pe", + "discord": "Discord" + } }, "toolBar": { "selection": "Selecție", @@ -303,7 +319,8 @@ "doubleClick": "dublu clic", "drag": "glisare", "editor": "Editor", - "editSelectedShape": "Editează forma selectată (text/săgeată/linie)", + "editLineArrowPoints": "Editare puncte de săgeată/rând", + "editText": "Editare text/adăugare etichetă", "github": "Ai întâmpinat o problemă? Trimite un raport", "howto": "Urmărește ghidurile noastre", "or": "sau", diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json index cd0609505..d4030897c 100644 --- a/src/locales/ru-RU.json +++ b/src/locales/ru-RU.json @@ -110,6 +110,7 @@ "increaseFontSize": "Увеличить шрифт", "unbindText": "Отвязать текст", "bindText": "Привязать текст к контейнеру", + "createContainerFromText": "", "link": { "edit": "Редактировать ссылку", "create": "Создать ссылку", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Не удалось подключиться к серверу совместного редактирования. Перезагрузите страницу и повторите попытку.", "importLibraryError": "Не удалось загрузить библиотеку", "collabSaveFailed": "Не удалось сохранить в базу данных. Если проблема повторится, нужно будет сохранить файл локально, чтобы быть уверенным, что вы не потеряете вашу работу.", - "collabSaveFailed_sizeExceeded": "Не удалось сохранить в базу данных. Похоже, что холст слишком большой. Нужно сохранить файл локально, чтобы быть уверенным, что вы не потеряете вашу работу." + "collabSaveFailed_sizeExceeded": "Не удалось сохранить в базу данных. Похоже, что холст слишком большой. Нужно сохранить файл локально, чтобы быть уверенным, что вы не потеряете вашу работу.", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Выделение области", @@ -303,7 +319,8 @@ "doubleClick": "двойной клик", "drag": "перетащить", "editor": "Редактор", - "editSelectedShape": "Редактировать выбранную фигуру (текст/стрелка/линия)", + "editLineArrowPoints": "", + "editText": "", "github": "Нашли проблему? Отправьте", "howto": "Следуйте нашим инструкциям", "or": "или", diff --git a/src/locales/si-LK.json b/src/locales/si-LK.json index ee6ad46f7..b84ad567f 100644 --- a/src/locales/si-LK.json +++ b/src/locales/si-LK.json @@ -110,6 +110,7 @@ "increaseFontSize": "", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { "edit": "", "create": "", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "", @@ -303,7 +319,8 @@ "doubleClick": "", "drag": "", "editor": "", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "", "howto": "", "or": "", diff --git a/src/locales/sk-SK.json b/src/locales/sk-SK.json index 2b78b4539..d6322ac1c 100644 --- a/src/locales/sk-SK.json +++ b/src/locales/sk-SK.json @@ -110,6 +110,7 @@ "increaseFontSize": "Zväčšiť veľkosť písma", "unbindText": "Zrušiť previazanie textu", "bindText": "Previazať text s kontajnerom", + "createContainerFromText": "Zabaliť text do kontajneru", "link": { "edit": "Upraviť odkaz", "create": "Vytvoriť odkaz", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Nepodarilo sa pripojiť ku kolaboračnému serveru. Prosím obnovte stránku a skúste to znovu.", "importLibraryError": "Nepodarilo sa načítať knižnicu", "collabSaveFailed": "Uloženie do databázy sa nepodarilo. Ak tento problém pretrváva uložte si váš súbor lokálne aby ste nestratili vašu prácu.", - "collabSaveFailed_sizeExceeded": "Uloženie do databázy sa nepodarilo, pretože veľkosť plátna je príliš veľká. Uložte si váš súbor lokálne aby ste nestratili vašu prácu." + "collabSaveFailed_sizeExceeded": "Uloženie do databázy sa nepodarilo, pretože veľkosť plátna je príliš veľká. Uložte si váš súbor lokálne aby ste nestratili vašu prácu.", + "brave_measure_text_error": { + "start": "Vyzerá to, že používate prehliadač Brave s", + "aggressive_block_fingerprint": "agresívnym blokovaním sledovania", + "setting_enabled": "zapnutým", + "break": "Toto môže znemožniť používanie", + "text_elements": "textových prvkov", + "in_your_drawings": "vo vašich kresbách", + "strongly_recommend": "Odporúčame vypnutie tohto nastavenia. Postupuje podľa", + "steps": "týchto krokov", + "how": "pre jeho vypnutie", + "disable_setting": " Ak sa vypnutím tohto nastavenia problém zobrazenia textových prvkov neodstráni, prosím vytvorte", + "issue": "issue", + "write": "na našom Github-e alebo nám to oznámte na", + "discord": "Discord" + } }, "toolBar": { "selection": "Výber", @@ -303,7 +319,8 @@ "doubleClick": "dvojklik", "drag": "potiahnutie", "editor": "Editovanie", - "editSelectedShape": "Editovať zvolený tvar (text/šípka/čiara)", + "editLineArrowPoints": "", + "editText": "", "github": "Objavili ste problém? Nahláste ho", "howto": "Postupujte podľa naších návodov", "or": "alebo", diff --git a/src/locales/sl-SI.json b/src/locales/sl-SI.json index 01c8ba4ca..57199c813 100644 --- a/src/locales/sl-SI.json +++ b/src/locales/sl-SI.json @@ -110,6 +110,7 @@ "increaseFontSize": "Povečaj velikost pisave", "unbindText": "Veži besedilo", "bindText": "Veži besedilo na element", + "createContainerFromText": "Zavij besedilo v vsebnik", "link": { "edit": "Uredi povezavo", "create": "Ustvari povezavo", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Povezave s strežnikom za sodelovanje ni bilo mogoče vzpostaviti. Ponovno naložite stran in poskusite znova.", "importLibraryError": "Nalaganje knjižnice ni uspelo", "collabSaveFailed": "Ni bilo mogoče shraniti v zaledno bazo podatkov. Če se težave nadaljujejo, shranite datoteko lokalno, da ne boste izgubili svojega dela.", - "collabSaveFailed_sizeExceeded": "Ni bilo mogoče shraniti v zaledno bazo podatkov, zdi se, da je platno preveliko. Datoteko shranite lokalno, da ne izgubite svojega dela." + "collabSaveFailed_sizeExceeded": "Ni bilo mogoče shraniti v zaledno bazo podatkov, zdi se, da je platno preveliko. Datoteko shranite lokalno, da ne izgubite svojega dela.", + "brave_measure_text_error": { + "start": "Videti je, da uporabljate brskalnik Brave z omogočeno nastavitvijo", + "aggressive_block_fingerprint": "Agresivno blokiranje prstnih odtisov", + "setting_enabled": " ", + "break": "To bi lahko povzročilo motnje v obnašanju", + "text_elements": "besedilnih elementov", + "in_your_drawings": "v vaših risbah", + "strongly_recommend": "Močno priporočamo, da onemogočite to nastavitev. Sledite", + "steps": "tem korakom,", + "how": "kako to storiti", + "disable_setting": " Če onemogočanje te nastavitve ne popravi prikaza besedilnih elementov, odprite", + "issue": "vprašanje", + "write": "na našem GitHubu ali nam pišite na", + "discord": "Discord" + } }, "toolBar": { "selection": "Izbor", @@ -303,7 +319,8 @@ "doubleClick": "dvojni klik", "drag": "vleci", "editor": "Urejevalnik", - "editSelectedShape": "Uredi izbrano obliko (besedilo/puščica/črta)", + "editLineArrowPoints": "Uredi črto/točke puščice", + "editText": "Uredi besedilo / dodaj oznako", "github": "Ste našli težavo? Pošljite", "howto": "Sledite našim vodičem", "or": "ali", diff --git a/src/locales/sv-SE.json b/src/locales/sv-SE.json index 3cf3b0cbd..d0392b119 100644 --- a/src/locales/sv-SE.json +++ b/src/locales/sv-SE.json @@ -110,6 +110,7 @@ "increaseFontSize": "Öka fontstorleken", "unbindText": "Koppla bort text", "bindText": "Bind texten till behållaren", + "createContainerFromText": "Radbryt text i en avgränsad yta", "link": { "edit": "Redigera länk", "create": "Skapa länk", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Det gick inte att ansluta till samarbets-servern. Ladda om sidan och försök igen.", "importLibraryError": "Kunde inte ladda bibliotek", "collabSaveFailed": "Det gick inte att spara i backend-databasen. Om problemen kvarstår bör du spara filen lokalt för att se till att du inte förlorar ditt arbete.", - "collabSaveFailed_sizeExceeded": "Det gick inte att spara till backend-databasen, whiteboarden verkar vara för stor. Du bör spara filen lokalt för att du inte ska förlora ditt arbete." + "collabSaveFailed_sizeExceeded": "Det gick inte att spara till backend-databasen, whiteboarden verkar vara för stor. Du bör spara filen lokalt för att du inte ska förlora ditt arbete.", + "brave_measure_text_error": { + "start": "Det ser ut som att du använder webbläsaren Brave med", + "aggressive_block_fingerprint": "Blockera \"Fingerprinting\" aggressivt", + "setting_enabled": "inställningen aktiverad", + "break": "Detta kan resultera i att ha sönder", + "text_elements": "Textelement", + "in_your_drawings": "i dina skisser", + "strongly_recommend": "Vi rekommenderar starkt att inaktivera denna inställning. Du kan följa", + "steps": "dessa steg", + "how": "om hur man gör det", + "disable_setting": " Om inaktivering av den här inställningen inte åtgärdar visningen av textelement, vänligen skapa ett", + "issue": "ärende", + "write": "på vår GitHub, eller skriv till oss på", + "discord": "Discord" + } }, "toolBar": { "selection": "Markering", @@ -303,7 +319,8 @@ "doubleClick": "dubbelklicka", "drag": "dra", "editor": "Redigerare", - "editSelectedShape": "Redigera markerad form (text/pil/linje)", + "editLineArrowPoints": "", + "editText": "", "github": "Hittat ett problem? Rapportera", "howto": "Följ våra guider", "or": "eller", diff --git a/src/locales/ta-IN.json b/src/locales/ta-IN.json index 493dfa560..6dc865766 100644 --- a/src/locales/ta-IN.json +++ b/src/locales/ta-IN.json @@ -110,6 +110,7 @@ "increaseFontSize": "எழுத்துரு அளவை அதிகரி", "unbindText": "உரையைப் பிணைவவிழ்", "bindText": "", + "createContainerFromText": "", "link": { "edit": "தொடுப்பைத் திருத்து", "create": "தொடுப்பைப் படை", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "நூலகத்தை ஏற்ற முடியவில்லை", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "தெரிவு", @@ -303,7 +319,8 @@ "doubleClick": "இரு-சொடுக்கு", "drag": "பிடித்திழு", "editor": "திருத்தி", - "editSelectedShape": "தேர்ந்த வடிவத்தைத் திருத்து (உரை/அம்பு/வரி)", + "editLineArrowPoints": "", + "editText": "", "github": "சிக்கலைக் கண்டீரா? சமர்ப்பி", "howto": "எங்கள் கையேடுகளைப் பின்பற்றுக", "or": "அ", diff --git a/src/locales/th-TH.json b/src/locales/th-TH.json new file mode 100644 index 000000000..2dcb9cb43 --- /dev/null +++ b/src/locales/th-TH.json @@ -0,0 +1,482 @@ +{ + "labels": { + "paste": "วาง", + "pasteAsPlaintext": "วางโดยไม่มีการจัดรูปแบบ", + "pasteCharts": "วางแผนภูมิ", + "selectAll": "เลือกทั้งหมด", + "multiSelect": "", + "moveCanvas": "", + "cut": "ตัด", + "copy": "คัดลอก", + "copyAsPng": "คัดลองไปยังคลิปบอร์ดเป็น PNG", + "copyAsSvg": "คัดลองไปยังคลิปบอร์ดเป็น SVG", + "copyText": "คัดลองไปยังคลิปบอร์ดเป็นข้อความ", + "bringForward": "นำขึ้นข้างบน", + "sendToBack": "ย้ายไปข้างล่าง", + "bringToFront": "นำขึ้นข้างหน้า", + "sendBackward": "ย้ายไปข้างหลัง", + "delete": "ลบ", + "copyStyles": "คัดลอกรูปแบบ", + "pasteStyles": "วางรูปแบบ", + "stroke": "เส้นขอบ", + "background": "พื้นหลัง", + "fill": "เติมสี", + "strokeWidth": "น้ำหนักเส้นขอบ", + "strokeStyle": "", + "strokeStyle_solid": "", + "strokeStyle_dashed": "", + "strokeStyle_dotted": "", + "sloppiness": "ความเลอะเทอะ", + "opacity": "ความทึบแสง", + "textAlign": "จัดข้อความ", + "edges": "ขอบ", + "sharp": "", + "round": "", + "arrowheads": "", + "arrowhead_none": "", + "arrowhead_arrow": "", + "arrowhead_bar": "", + "arrowhead_dot": "", + "arrowhead_triangle": "", + "fontSize": "ขนาดตัวอักษร", + "fontFamily": "แบบตัวอักษร", + "onlySelected": "เฉพาะที่เลือก", + "withBackground": "พื้นหลัง", + "exportEmbedScene": "", + "exportEmbedScene_details": "", + "addWatermark": "เพิ่มลายน้ำ \"สร้างด้วย Excalidraw\"", + "handDrawn": "ลายมือ", + "normal": "ปกติ", + "code": "โค้ด", + "small": "เล็ก", + "medium": "กลาง", + "large": "ใหญ่", + "veryLarge": "ใหญ่มาก", + "solid": "", + "hachure": "", + "crossHatch": "", + "thin": "บาง", + "bold": "หนา", + "left": "ซ้าย", + "center": "กลาง", + "right": "ขวา", + "extraBold": "หนาพิเศษ", + "architect": "", + "artist": "", + "cartoonist": "", + "fileTitle": "ชื่อไฟล์", + "colorPicker": "เลือกสีที่กำหนดเอง", + "canvasColors": "", + "canvasBackground": "", + "drawingCanvas": "", + "layers": "", + "actions": "การกระทำ", + "language": "ภาษา", + "liveCollaboration": "", + "duplicateSelection": "ทำสำเนา", + "untitled": "ไม่มีชื่อ", + "name": "ชื่อ", + "yourName": "ชื่อของคุณ", + "madeWithExcalidraw": "", + "group": "จัดกลุ่ม", + "ungroup": "ยกเลิกการจัดกลุ่ม", + "collaborators": "", + "showGrid": "แสดงเส้นตาราง", + "addToLibrary": "เพิ่มไปในคลัง", + "removeFromLibrary": "นำออกจากคลัง", + "libraryLoadingMessage": "กำลังโหลดคลัง...", + "libraries": "", + "loadingScene": "กำลังโหลดฉาก", + "align": "จัดตำแหน่ง", + "alignTop": "จัดชิดด้านบน", + "alignBottom": "จัดชิดด้านล่าง", + "alignLeft": "จัดชิดซ้าย", + "alignRight": "จัดชิดขวา", + "centerVertically": "กึ่งกลางแนวตั้ง", + "centerHorizontally": "กึ่งกลางแนวนอน", + "distributeHorizontally": "กระจายแนวนอน", + "distributeVertically": "กระจายแนวตั้ง", + "flipHorizontal": "พลิกแนวนอน", + "flipVertical": "พลิกแนวตั้ง", + "viewMode": "โหมดมุมมอง", + "toggleExportColorScheme": "", + "share": "แชร์", + "showStroke": "", + "showBackground": "", + "toggleTheme": "สลับธีม", + "personalLib": "คลังของฉัน", + "excalidrawLib": "คลังของ Excalidraw", + "decreaseFontSize": "ลดขนาดตัวอักษร", + "increaseFontSize": "เพิ่มขนาดตัวอักษร", + "unbindText": "", + "bindText": "", + "createContainerFromText": "", + "link": { + "edit": "แก้ไขลิงก์", + "create": "สร้างลิงค์", + "label": "ลิงค์" + }, + "lineEditor": { + "edit": "แก้ไขเส้น", + "exit": "" + }, + "elementLock": { + "lock": "ล็อก", + "unlock": "ปลดล็อก", + "lockAll": "ล็อกทั้งหมด", + "unlockAll": "ปลดล็อกทั้งหมด" + }, + "statusPublished": "เผยแพร่", + "sidebarLock": "" + }, + "library": { + "noItems": "", + "hint_emptyLibrary": "", + "hint_emptyPrivateLibrary": "" + }, + "buttons": { + "clearReset": "", + "exportJSON": "ส่งออกไปยังไฟล์", + "exportImage": "ส่งออกเป็นรูปภาพ", + "export": "บันทึกไปยัง", + "exportToPng": "ส่งออกไปเป็น PNG", + "exportToSvg": "ส่งออกไปเป็น SVG", + "copyToClipboard": "คัดลอกไปยังคลิปบอร์ด", + "copyPngToClipboard": "คัดลอก PNG ไปยังคลิปบอร์ด", + "scale": "อัตราส่วน", + "save": "", + "saveAs": "", + "load": "เปิด", + "getShareableLink": "สร้างลิงค์ที่แชร์ได้", + "close": "ปิด", + "selectLanguage": "เลือกภาษา", + "scrollBackToContent": "เลื่อนกลับไปด้านบน", + "zoomIn": "ซูมเข้า", + "zoomOut": "ซูมออก", + "resetZoom": "รีเซ็ตการซูม", + "menu": "เมนู", + "done": "เสร็จสิ้น", + "edit": "แก้ไข", + "undo": "เลิกทำ", + "redo": "ทำซ้ำ", + "resetLibrary": "รีเซ็ตคลัง", + "createNewRoom": "สร้างห้องใหม่", + "fullScreen": "เต็มหน้าจอ", + "darkMode": "โหมดกลางคืน", + "lightMode": "โหมดกลางวัน", + "zenMode": "โหมด Zen", + "exitZenMode": "ออกจากโหมด Zen", + "cancel": "ยกเลิก", + "clear": "เคลียร์", + "remove": "ลบ", + "publishLibrary": "เผยแพร่", + "submit": "ตกลง", + "confirm": "ยืนยัน" + }, + "alerts": { + "clearReset": "", + "couldNotCreateShareableLink": "", + "couldNotCreateShareableLinkTooBig": "", + "couldNotLoadInvalidFile": "ไม่สามารถโหลดไฟล์ที่ผิดพลาดได้", + "importBackendFailed": "", + "cannotExportEmptyCanvas": "", + "couldNotCopyToClipboard": "ไม่สามารถคัดลอกไปยังคลิปบอร์ดได้", + "decryptFailed": "ไม่สามารถถอดรหัสข้อมูลได้", + "uploadedSecurly": "การอัพโหลดได้ถูกเข้ารหัสแบบ end-to-end หมายความว่าเซิร์ฟเวอร์ของ Excalidraw และบุคคลอื่นไม่สามารถอ่านข้อมูลได้", + "loadSceneOverridePrompt": "", + "collabStopOverridePrompt": "", + "errorAddingToLibrary": "ไม่สามารถเพิ่มรายการเข้าไปในคลังได้", + "errorRemovingFromLibrary": "ไม่สามารถลบรายการนี้ออกจากคลังได้", + "confirmAddLibrary": "", + "imageDoesNotContainScene": "", + "cannotRestoreFromImage": "", + "invalidSceneUrl": "", + "resetLibrary": "", + "removeItemsFromsLibrary": "", + "invalidEncryptionKey": "", + "collabOfflineWarning": "" + }, + "errors": { + "unsupportedFileType": "ไม่รองรับชนิดของไฟล์นี้", + "imageInsertError": "ไม่สามารถเพิ่มรูปภาพได้ ลองอีกครั้งในภายหลัง", + "fileTooBig": "", + "svgImageInsertError": "", + "invalidSVGString": "ไฟล์ SVG ผิดพลาด", + "cannotResolveCollabServer": "ไม่สามารถเชื่อต่อกับ collab เซิร์ฟเวอร์ได้ โปรดลองโหลดหน้านี้ใหม่และลองอีกครั้ง", + "importLibraryError": "", + "collabSaveFailed": "", + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "Discord" + } + }, + "toolBar": { + "selection": "", + "image": "", + "rectangle": "สี่เหลี่ยมผืนผ้า", + "diamond": "", + "ellipse": "", + "arrow": "", + "line": "", + "freedraw": "", + "text": "ข้อความ", + "library": "คลัง", + "lock": "", + "penMode": "", + "link": "", + "eraser": "ยางลบ", + "hand": "" + }, + "headings": { + "canvasActions": "", + "selectedShapeActions": "", + "shapes": "รูปร่าง" + }, + "hints": { + "canvasPanning": "", + "linearElement": "", + "freeDraw": "", + "text": "", + "text_selected": "คลิกสองครั้งหรือกด ENTER เพื่อแก้ไขข้อความ", + "text_editing": "กดปุ่ม Esc หรือกด Ctrl, Cmd + Enter เพื่อเสร็จการแก้ไข", + "linearElementMulti": "คลิกที่จุดสุดท้ายหรือกด Escape หรือ Enter เพื่อเสร็จสิ้น", + "lockAngle": "", + "resize": "", + "resizeImage": "", + "rotate": "", + "lineEditor_info": "", + "lineEditor_pointSelected": "กดปุ่ม Delete เพื่อลบจุด\nกด Ctrl หรือ Cmd + D เพื่อทำซ้ำหรือลากเพื่อเคลื่อนย้าย", + "lineEditor_nothingSelected": "", + "placeImage": "", + "publishLibrary": "", + "bindTextToElement": "", + "deepBoxSelect": "", + "eraserRevert": "", + "firefox_clipboard_write": "" + }, + "canvasError": { + "cannotShowPreview": "", + "canvasTooBig": "", + "canvasTooBigTip": "" + }, + "errorSplash": { + "headingMain_pre": "", + "headingMain_button": "กำลังรีโหลดหน้า", + "clearCanvasMessage": "ถ้าโหลดไม่ได้ ให้ลอง ", + "clearCanvasMessage_button": "เคลียร์ผืนผ้าใบ", + "clearCanvasCaveat": "", + "trackedToSentry_pre": "", + "trackedToSentry_post": "", + "openIssueMessage_pre": "", + "openIssueMessage_button": "", + "openIssueMessage_post": "", + "sceneContent": "" + }, + "roomDialog": { + "desc_intro": "", + "desc_privacy": "", + "button_startSession": "เริ่มเซสชัน", + "button_stopSession": "หยุดเซสชัน", + "desc_inProgressIntro": "", + "desc_shareLink": "", + "desc_exitSession": "", + "shareTitle": "" + }, + "errorDialog": { + "title": "" + }, + "exportDialog": { + "disk_title": "", + "disk_details": "", + "disk_button": "", + "link_title": "", + "link_details": "", + "link_button": "", + "excalidrawplus_description": "", + "excalidrawplus_button": "", + "excalidrawplus_exportError": "ไม่สามารถส่งออกไปที่ Excalidraw+ ได้ในขณะนี้" + }, + "helpDialog": { + "blog": "อ่านบล็อกของพวกเรา", + "click": "คลิก", + "deepSelect": "", + "deepBoxSelect": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "doubleClick": "ดับเบิลคลิก", + "drag": "ลาก", + "editor": "", + "editLineArrowPoints": "", + "editText": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "tools": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "ช่วยเหลือ", + "view": "ดู", + "zoomToFit": "", + "zoomToSelection": "", + "toggleElementLock": "", + "movePageUpDown": "", + "movePageLeftRight": "ย้ายหน้าไปด้าน ซ้าย/ขวา" + }, + "clearCanvasDialog": { + "title": "" + }, + "publishDialog": { + "title": "", + "itemName": "", + "authorName": "ชื่อเจ้าของ", + "githubUsername": "ชื่อผู้ใช้ GitHub", + "twitterUsername": "ชื่อผู้ใช้ Twitter", + "libraryName": "", + "libraryDesc": "", + "website": "", + "placeholder": { + "authorName": "", + "libraryName": "", + "libraryDesc": "", + "githubHandle": "", + "twitterHandle": "", + "website": "" + }, + "errors": { + "required": "", + "website": "" + }, + "noteDescription": { + "pre": "", + "link": "", + "post": "" + }, + "noteGuidelines": { + "pre": "", + "link": "", + "post": "" + }, + "noteLicense": { + "pre": "", + "link": "", + "post": "" + }, + "noteItems": "", + "atleastOneLibItem": "", + "republishWarning": "" + }, + "publishSuccessDialog": { + "title": "", + "content": "", + "link": "" + }, + "confirmDialog": { + "resetLibrary": "", + "removeItemsFromLib": "" + }, + "encrypted": { + "tooltip": "", + "link": "" + }, + "stats": { + "angle": "", + "element": "", + "elements": "", + "height": "", + "scene": "", + "selected": "", + "storage": "", + "title": "", + "total": "", + "version": "", + "versionCopy": "", + "versionNotAvailable": "", + "width": "" + }, + "toast": { + "addedToLibrary": "", + "copyStyles": "", + "copyToClipboard": "", + "copyToClipboardAsPng": "", + "fileSaved": "", + "fileSavedToFilename": "", + "canvas": "", + "selection": "", + "pasteAsSingleElement": "" + }, + "colors": { + "ffffff": "สีขาว", + "f8f9fa": "สีเทา 0", + "f1f3f5": "สีเทา 1", + "fff5f5": "สีแดง 0", + "fff0f6": "สีชมพู 0", + "f8f0fc": "", + "f3f0ff": "", + "edf2ff": "", + "e7f5ff": "", + "e3fafc": "", + "e6fcf5": "", + "ebfbee": "", + "f4fce3": "", + "fff9db": "", + "fff4e6": "", + "transparent": "", + "ced4da": "สีเทา 4", + "868e96": "สีเทา 6", + "fa5252": "สีแดง 6", + "e64980": "สีชมพู 6", + "be4bdb": "", + "7950f2": "", + "4c6ef5": "", + "228be6": "", + "15aabf": "", + "12b886": "", + "40c057": "", + "82c91e": "", + "fab005": "", + "fd7e14": "", + "000000": "", + "343a40": "", + "495057": "", + "c92a2a": "", + "a61e4d": "", + "862e9c": "", + "5f3dc4": "", + "364fc7": "", + "1864ab": "", + "0b7285": "", + "087f5b": "", + "2b8a3e": "", + "5c940d": "", + "e67700": "", + "d9480f": "" + }, + "welcomeScreen": { + "app": { + "center_heading": "", + "center_heading_plus": "", + "menuHint": "" + }, + "defaults": { + "menuHint": "", + "center_heading": "", + "toolbarHint": "", + "helpHint": "" + } + } +} diff --git a/src/locales/tr-TR.json b/src/locales/tr-TR.json index a05de9a54..78dd9329a 100644 --- a/src/locales/tr-TR.json +++ b/src/locales/tr-TR.json @@ -66,7 +66,7 @@ "cartoonist": "Karikatürist", "fileTitle": "Dosya adı", "colorPicker": "Renk seçici", - "canvasColors": "Tuvallerin üzerinde kullanıldı", + "canvasColors": "Tuvalin üzerinde kullanıldı", "canvasBackground": "Tuval arka planı", "drawingCanvas": "Çizim tuvali", "layers": "Katmanlar", @@ -110,6 +110,7 @@ "increaseFontSize": "Yazı Tipi Boyutunu Büyült", "unbindText": "Metni çöz", "bindText": "Metni taşıyıcıya bağla", + "createContainerFromText": "", "link": { "edit": "Bağlantıyı düzenle", "create": "Bağlantı oluştur", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "İş birliği sunucusuna bağlanılamıyor. Lütfen sayfayı yenileyip tekrar deneyin.", "importLibraryError": "Kütüphane yüklenemedi", "collabSaveFailed": "Backend veritabanına kaydedilemedi. Eğer problem devam ederse, çalışmanızı korumak için dosyayı yerel olarak kaydetmelisiniz.", - "collabSaveFailed_sizeExceeded": "Backend veritabanına kaydedilemedi; tuval çok büyük. Çalışmanızı korumak için dosyayı yerel olarak kaydetmelisiniz." + "collabSaveFailed_sizeExceeded": "Backend veritabanına kaydedilemedi; tuval çok büyük. Çalışmanızı korumak için dosyayı yerel olarak kaydetmelisiniz.", + "brave_measure_text_error": { + "start": "Görünüşe göre Brave gezginini", + "aggressive_block_fingerprint": "Agresif parmakizi bloklama", + "setting_enabled": "ayarları etkin şeklide kullanıyor gibisiniz", + "break": "Bu bir takım sorunlara yol açabilir", + "text_elements": "Metin elementlerinde bozulma", + "in_your_drawings": "çizimlerde bozulma gibi", + "strongly_recommend": "Bu ayarı devre dışı bırakmanızı şiddetle öneririz. Şu adımları", + "steps": "takip ederek", + "how": "nasıl yapılacağını", + "disable_setting": " Yapabilirsiniz. Eğer devre dışı bırakmak işe yaramazsa, lütfen", + "issue": "konu hakkında", + "write": "github'da sorun belirtin, ya da bize", + "discord": "Discord üzerinden iletin" + } }, "toolBar": { "selection": "Seçme", @@ -303,7 +319,8 @@ "doubleClick": "çift-tıklama", "drag": "sürükle", "editor": "Düzenleyici", - "editSelectedShape": "Seçili şekli düzenle (metin/ok/çizgi)", + "editLineArrowPoints": "Çizgi/ok noktalarını düzenle", + "editText": "Etiket / metin düzenle", "github": "Bir hata mı buldun? Bildir", "howto": "Rehberlerimizi takip edin", "or": "veya", @@ -453,13 +470,13 @@ "app": { "center_heading": "", "center_heading_plus": "", - "menuHint": "" + "menuHint": "Dışa aktar, seçenekler, diller, ..." }, "defaults": { - "menuHint": "", + "menuHint": "Dışa aktar, seçenekler, ve daha fazlası...", "center_heading": "", - "toolbarHint": "", - "helpHint": "" + "toolbarHint": "Bir araç seçin ve çizime başlayın!", + "helpHint": "Kısayollar & yardım" } } } diff --git a/src/locales/uk-UA.json b/src/locales/uk-UA.json index ac0bfcfee..ed1a01e68 100644 --- a/src/locales/uk-UA.json +++ b/src/locales/uk-UA.json @@ -110,6 +110,7 @@ "increaseFontSize": "Збільшити розмір шрифту", "unbindText": "Відв'язати текст", "bindText": "Прив’язати текст до контейнера", + "createContainerFromText": "", "link": { "edit": "Редагування посилання", "create": "Створити посилання", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "Не вдалося приєднатися до сервера. Перезавантажте сторінку та повторіть спробу.", "importLibraryError": "Не вдалося завантажити бібліотеку", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "Виділення", @@ -303,7 +319,8 @@ "doubleClick": "подвійний клік", "drag": "перетягнути", "editor": "Редактор", - "editSelectedShape": "Змінити вибрану фігуру (текст/стрілку/рядок)", + "editLineArrowPoints": "", + "editText": "", "github": "Знайшли помилку? Повідомте", "howto": "Дотримуйтесь наших інструкцій", "or": "або", diff --git a/src/locales/vi-VN.json b/src/locales/vi-VN.json index 1921035bc..887c32e3e 100644 --- a/src/locales/vi-VN.json +++ b/src/locales/vi-VN.json @@ -5,7 +5,7 @@ "pasteCharts": "Dán biểu đồ", "selectAll": "Chọn tất cả", "multiSelect": "Thêm mới vào Select", - "moveCanvas": "Di chuyển Canvas", + "moveCanvas": "Di chuyển canvas", "cut": "Cắt", "copy": "Sao chép", "copyAsPng": "Sao chép vào bộ nhớ tạm dưới dạng PNG", @@ -60,11 +60,11 @@ "left": "Trái", "center": "Giữa", "right": "Phải", - "extraBold": "", + "extraBold": "Nét siêu đậm", "architect": "Kiến trúc sư", "artist": "Nghệ sỹ", "cartoonist": "Hoạt hình", - "fileTitle": "", + "fileTitle": "Tên tập tin", "colorPicker": "Chọn màu", "canvasColors": "Đã dùng trên canvas", "canvasBackground": "Nền canvas", @@ -72,28 +72,28 @@ "layers": "Lớp", "actions": "Chức năng", "language": "Ngôn ngữ", - "liveCollaboration": "", + "liveCollaboration": "Hợp tác trực tiếp...", "duplicateSelection": "Tạo bản sao", "untitled": "Không có tiêu đề", "name": "Tên", "yourName": "Tên của bạn", "madeWithExcalidraw": "Làm với Excalidraw", - "group": "", - "ungroup": "", + "group": "Gộp nhóm lại lựa chọn", + "ungroup": "Tách nhóm lựa chọn", "collaborators": "Cộng tác viên", - "showGrid": "", - "addToLibrary": "", - "removeFromLibrary": "", - "libraryLoadingMessage": "", - "libraries": "", + "showGrid": "Hiển thị lưới", + "addToLibrary": "Thêm vào thư viện", + "removeFromLibrary": "Xóa khỏi thư viện", + "libraryLoadingMessage": "Đang tải thư viện…", + "libraries": "Xem thư viện", "loadingScene": "", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", + "align": "Căn chỉnh", + "alignTop": "Căn trên", + "alignBottom": "Căn dưới", + "alignLeft": "Canh trái", + "alignRight": "Canh phải", + "centerVertically": "Giữa theo chiều dọc", + "centerHorizontally": "Giữa theo chiều ngang", "distributeHorizontally": "Phân bố theo chiều ngang", "distributeVertically": "Phân bố theo chiều dọc", "flipHorizontal": "Lật ngang", @@ -105,42 +105,43 @@ "showBackground": "Hiện thị chọn màu nền", "toggleTheme": "", "personalLib": "", - "excalidrawLib": "", - "decreaseFontSize": "", - "increaseFontSize": "", + "excalidrawLib": "Thư viện Excalidraw", + "decreaseFontSize": "Giảm cỡ chữ", + "increaseFontSize": "Tăng cỡ chữ", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { - "edit": "", - "create": "", - "label": "" + "edit": "Sửa liên kết", + "create": "Tạo liên kết", + "label": "Liên kết" }, "lineEditor": { - "edit": "", - "exit": "" + "edit": "Điều chỉnh nét", + "exit": "Thoát chỉnh nét" }, "elementLock": { - "lock": "", - "unlock": "", - "lockAll": "", - "unlockAll": "" + "lock": "Khoá", + "unlock": "Mở khoá", + "lockAll": "Khóa tất cả", + "unlockAll": "Mở khóa tất cả" }, - "statusPublished": "", - "sidebarLock": "" + "statusPublished": "Đã đăng tải", + "sidebarLock": "Giữ thanh bên luôn mở" }, "library": { - "noItems": "", - "hint_emptyLibrary": "", - "hint_emptyPrivateLibrary": "" + "noItems": "Chưa có món nào...", + "hint_emptyLibrary": "Chọn một món trên canvas để thêm nó vào đây, hoặc cài đặt thư viện từ kho lưu trữ công cộng, ở bên dưới.", + "hint_emptyPrivateLibrary": "Chọn một món trên canvas để thêm nó vào đây." }, "buttons": { - "clearReset": "", - "exportJSON": "", - "exportImage": "", - "export": "", - "exportToPng": "", - "exportToSvg": "", - "copyToClipboard": "", + "clearReset": "Reset canvas", + "exportJSON": "Xuất ra tập tin", + "exportImage": "Xuất file ảnh...", + "export": "Lưu vào...", + "exportToPng": "Xuất ra tập tin PNG", + "exportToSvg": "Xuất ra tập tin SVG", + "copyToClipboard": "Sao chép vào bộ nhớ tạm", "copyPngToClipboard": "", "scale": "", "save": "", @@ -160,84 +161,99 @@ "redo": "", "resetLibrary": "", "createNewRoom": "", - "fullScreen": "", - "darkMode": "", - "lightMode": "", - "zenMode": "", - "exitZenMode": "", - "cancel": "", - "clear": "", - "remove": "", - "publishLibrary": "", - "submit": "", - "confirm": "" + "fullScreen": "Toàn màn hình", + "darkMode": "Chế độ tối", + "lightMode": "Chế độ sáng", + "zenMode": "Chế độ zen", + "exitZenMode": "Thoát chể độ zen", + "cancel": "Hủy", + "clear": "Làm sạch", + "remove": "Xóa", + "publishLibrary": "Đăng tải", + "submit": "Gửi", + "confirm": "Xác nhận" }, "alerts": { - "clearReset": "", - "couldNotCreateShareableLink": "", - "couldNotCreateShareableLinkTooBig": "", - "couldNotLoadInvalidFile": "", + "clearReset": "Điều này sẽ dọn hết canvas. Bạn có chắc không?", + "couldNotCreateShareableLink": "Không thể tạo đường dẫn chia sẻ.", + "couldNotCreateShareableLinkTooBig": "Không thể tạo đường dẫn chia sẻ: bản vẽ quá lớn", + "couldNotLoadInvalidFile": "Không thể load tập tin không hợp lệ", "importBackendFailed": "", - "cannotExportEmptyCanvas": "", + "cannotExportEmptyCanvas": "Không thể xuất canvas trống.", "couldNotCopyToClipboard": "", "decryptFailed": "", "uploadedSecurly": "", "loadSceneOverridePrompt": "", - "collabStopOverridePrompt": "", - "errorAddingToLibrary": "", - "errorRemovingFromLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", + "collabStopOverridePrompt": "Dừng phiên sẽ ghi đè lên bản vẽ được lưu trữ cục bộ trước đó của bạn. Bạn có chắc không?\n\n(Nếu bạn muốn giữ bản vẽ cục bộ của mình, chỉ cần đóng tab trình duyệt.)", + "errorAddingToLibrary": "Không thể thêm món vào thư viện", + "errorRemovingFromLibrary": "Không thể xoá món khỏi thư viện", + "confirmAddLibrary": "Hình {{numShapes}} sẽ được thêm vào thư viện. Bạn chắc chứ?", + "imageDoesNotContainScene": "Hình ảnh này dường như không chứa bất kỳ dữ liệu cảnh nào. Bạn đã bật tính năng nhúng cảnh khi xuất chưa?", "cannotRestoreFromImage": "", "invalidSceneUrl": "", "resetLibrary": "", - "removeItemsFromsLibrary": "", - "invalidEncryptionKey": "", - "collabOfflineWarning": "" + "removeItemsFromsLibrary": "Xoá {{count}} món từ thư viện?", + "invalidEncryptionKey": "Khóa mã hóa phải có 22 ký tự. Hợp tác trực tiếp bị vô hiệu hóa.", + "collabOfflineWarning": "Không có kết nối internet.\nThay đổi của bạn sẽ không được lưu!" }, "errors": { - "unsupportedFileType": "", - "imageInsertError": "", - "fileTooBig": "", - "svgImageInsertError": "", - "invalidSVGString": "", - "cannotResolveCollabServer": "", - "importLibraryError": "", - "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "unsupportedFileType": "Loại tập tin không được hỗ trợ.", + "imageInsertError": "Không thể thêm ảnh. Hãy thử lại sau...", + "fileTooBig": "Tệp tin quá lớn. Dung lượng tối đa cho phép là {{maxSize}}.", + "svgImageInsertError": "Không thể thêm ảnh SVG. Mã SVG có vẻ sai.", + "invalidSVGString": "SVG không hợp lệ.", + "cannotResolveCollabServer": "Không thể kết nối với máy chủ hợp tác. Hãy tải lại trang và thử lại.", + "importLibraryError": "Không thể tải thư viện", + "collabSaveFailed": "Không thể lưu vào cơ sở dữ liệu. Nếu vấn đề tiếp tục xảy ra, bạn nên lưu tệp vào máy để đảm bảo bạn không bị mất công việc.", + "collabSaveFailed_sizeExceeded": "Không thể lưu vào cơ sở dữ liệu, canvas có vẻ quá lớn. Bạn nên lưu tệp cục bộ để đảm bảo bạn không bị mất công việc.", + "brave_measure_text_error": { + "start": "Có vẻ bạn đang sử dụng trình duyện Brave với chức năng", + "aggressive_block_fingerprint": "Aggressively Block Fingerprinting", + "setting_enabled": "được bật", + "break": "Điều này có thể xảy ra lỗi các", + "text_elements": "Yếu Tố Chữ", + "in_your_drawings": "trong bản vẽ của bạn", + "strongly_recommend": "Chúng tôi khuyên rằng bạn nên tắt chức năng này. Bạn có thể theo", + "steps": "các bước sau đây", + "how": "để tắt nó", + "disable_setting": " Nếu tắt chức năng này vẫn không sửa lại lỗi hiện thị các yếu tố chữ, hảy mở", + "issue": "issue", + "write": "trên trang GitHUb của chúng tôi, hoặc nhắn chúng tôi tại", + "discord": "Discord" + } }, "toolBar": { - "selection": "", - "image": "", - "rectangle": "", - "diamond": "", - "ellipse": "", - "arrow": "", - "line": "", - "freedraw": "", - "text": "", - "library": "", - "lock": "", - "penMode": "", - "link": "", - "eraser": "", - "hand": "" + "selection": "Lựa chọn", + "image": "Chèn ảnh", + "rectangle": "Hình chữ nhật", + "diamond": "Kim cương", + "ellipse": "Hình elíp", + "arrow": "Mũi tên", + "line": "Đường kẻ", + "freedraw": "Vẽ", + "text": "Văn bản", + "library": "Thư viện", + "lock": "Giữ dụng cũ hiện tại sau khi vẽ", + "penMode": "Chế độ bút vẽ - ngăn ngừa chạm nhầm", + "link": "Thêm/ Chỉnh sửa liên kết cho hình được chọn", + "eraser": "Xóa", + "hand": "Tay kéo" }, "headings": { - "canvasActions": "", - "selectedShapeActions": "", - "shapes": "" + "canvasActions": "Hành động canvas", + "selectedShapeActions": "Các hành động cho hình dạng đã chọn", + "shapes": "Các hình khối" }, "hints": { - "canvasPanning": "", - "linearElement": "", - "freeDraw": "", - "text": "", - "text_selected": "", - "text_editing": "", - "linearElementMulti": "", - "lockAngle": "", - "resize": "", + "canvasPanning": "Để di chuyển canvas, giữ con lăn chuột hoặc phím cách trong khi kéo, hoặc sử dụng công cụ cầm tay", + "linearElement": "Ấn để bắt đầu nhiểm điểm vẽ, kéo để vẽ một đường thẳng", + "freeDraw": "Ấn bà kéo, thả khi bạn xong", + "text": "Mẹo: bạn có thể thêm văn bản tại bất cứ đâu bằng cách ấn hai lần bằng tool lựa chọn", + "text_selected": "Ấn 2 lần hoặc nhấn ENTER để chỉnh văn bản", + "text_editing": "Nhấn Escape hoặc Ctrl/Cmd+ENTER để hoàn thành chỉnh sửa", + "linearElementMulti": "Nhấn vào điểm cuối hoặc nhấn Escape hoặc Enter để kết thúc", + "lockAngle": "Bạn có thể chỉnh lại góc bằng cách giữ phím SHIFT", + "resize": "Bạn có thể chỉnh tỷ lệ bằng cách giữ SHIFT khi chỉnh kích cỡ,\ngiữ ALT để chỉnh kích cỡ từ trung tâm", "resizeImage": "", "rotate": "", "lineEditor_info": "", @@ -248,19 +264,19 @@ "bindTextToElement": "", "deepBoxSelect": "", "eraserRevert": "", - "firefox_clipboard_write": "" + "firefox_clipboard_write": "Tính năng này có thể được bật bằng cách đặt cờ \"dom.events.asyncClipboard.clipboardItem\" thành \"true\". Để thay đổi cờ trình duyệt trong Firefox, hãy truy cập trang \"about:config\"." }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Không thể xem trước", + "canvasTooBig": "Canvas này có thể hơi lớn.", + "canvasTooBigTip": "Mẹo: hãy thử di chuyển các elements nhất lại gần nhau hơn một chút." }, "errorSplash": { "headingMain_pre": "", "headingMain_button": "", - "clearCanvasMessage": "", - "clearCanvasMessage_button": "", - "clearCanvasCaveat": "", + "clearCanvasMessage": "Nếu không tải lại được, hãy thử ", + "clearCanvasMessage_button": "dọn canvas.", + "clearCanvasCaveat": " Điều này sẽ dẫn đến mất dữ liệu bạn đã làm ", "trackedToSentry_pre": "", "trackedToSentry_post": "", "openIssueMessage_pre": "", @@ -303,7 +319,8 @@ "doubleClick": "", "drag": "", "editor": "", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "", "howto": "", "or": "", @@ -321,11 +338,11 @@ "movePageLeftRight": "" }, "clearCanvasDialog": { - "title": "" + "title": "Dọn canvas" }, "publishDialog": { "title": "", - "itemName": "", + "itemName": "Tên món", "authorName": "", "githubUsername": "", "twitterUsername": "", @@ -359,9 +376,9 @@ "link": "", "post": "" }, - "noteItems": "", - "atleastOneLibItem": "", - "republishWarning": "" + "noteItems": "Từng món trong thư viện phải có tên riêng để có thể lọc. Các món thư viện sau đây sẽ thêm:", + "atleastOneLibItem": "Vui lòng chọn ít nhất một món thư viện để bắt đầu", + "republishWarning": "Lưu ý: một số món đã chọn được đánh dấu là đã xuất bản/đã gửi. Bạn chỉ nên gửi lại các món khi cập nhật thư viện hiện có hoặc gửi." }, "publishSuccessDialog": { "title": "", @@ -370,7 +387,7 @@ }, "confirmDialog": { "resetLibrary": "", - "removeItemsFromLib": "" + "removeItemsFromLib": "Xóa món đã chọn khỏi thư viện" }, "encrypted": { "tooltip": "", @@ -398,7 +415,7 @@ "copyToClipboardAsPng": "", "fileSaved": "", "fileSavedToFilename": "", - "canvas": "", + "canvas": "canvas", "selection": "", "pasteAsSingleElement": "" }, @@ -440,14 +457,14 @@ "a61e4d": "", "862e9c": "", "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "364fc7": "Chàm 9", + "1864ab": "Xanh Dương 9", + "0b7285": "Lục Lam 9", + "087f5b": "Xanh Mòng Két 9", + "2b8a3e": "Xanh Lá 9", + "5c940d": "Chanh Xanh 9", + "e67700": "Vàng 9", + "d9480f": "Cam 9" }, "welcomeScreen": { "app": { diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 2e5debd16..5863f5ceb 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -35,12 +35,12 @@ "arrowheads": "端点", "arrowhead_none": "无", "arrowhead_arrow": "箭头", - "arrowhead_bar": "条", + "arrowhead_bar": "条状", "arrowhead_dot": "圆点", "arrowhead_triangle": "三角箭头", "fontSize": "字体大小", "fontFamily": "字体", - "onlySelected": "仅被选中", + "onlySelected": "仅选中", "withBackground": "背景", "exportEmbedScene": "包含画布数据", "exportEmbedScene_details": "画布数据将被保存到导出的 PNG/SVG 文件,以便恢复。\n将会增加导出的文件大小。", @@ -110,6 +110,7 @@ "increaseFontSize": "放大字体大小", "unbindText": "取消文本绑定", "bindText": "将文本绑定到容器", + "createContainerFromText": "将文本包围在容器中", "link": { "edit": "编辑链接", "create": "新建链接", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "无法连接到实时协作服务器。请重新加载页面并重试。", "importLibraryError": "无法加载素材库", "collabSaveFailed": "无法保存到后端数据库。如果问题持续存在,您应该保存文件到本地,以确保您的工作不会丢失。", - "collabSaveFailed_sizeExceeded": "无法保存到后端数据库,画布似乎过大。您应该保存文件到本地,以确保您的工作不会丢失。" + "collabSaveFailed_sizeExceeded": "无法保存到后端数据库,画布似乎过大。您应该保存文件到本地,以确保您的工作不会丢失。", + "brave_measure_text_error": { + "start": "看起来您正在使用 Brave 浏览器并启用了", + "aggressive_block_fingerprint": "积极阻止指纹识别", + "setting_enabled": "设置", + "break": "这可能会破坏绘图中的", + "text_elements": "文本元素", + "in_your_drawings": " ", + "strongly_recommend": "我们强烈建议禁用此设置。您可以按照", + "steps": "这些步骤", + "how": "来设置", + "disable_setting": " 如果禁用此设置无法修复文本元素的显示,请在 GitHub 提交一个", + "issue": "issue", + "write": ",或者通过", + "discord": "Discord 反馈" + } }, "toolBar": { "selection": "选择", @@ -248,7 +264,7 @@ "bindTextToElement": "按下 Enter 以添加文本", "deepBoxSelect": "按住 CtrlOrCmd 以深度选择,并避免拖拽", "eraserRevert": "按住 Alt 以反选被标记删除的元素", - "firefox_clipboard_write": "将高级配置首选项“dom.events.asyncClipboard.lipboarditem”设置为“true”可以启用此功能。要更改 Firefox 的高级配置首选项,请前往“about:config”页面。" + "firefox_clipboard_write": "将高级配置首选项“dom.events.asyncClipboard.clipboardItem”设置为“true”可以启用此功能。要更改 Firefox 的高级配置首选项,请前往“about:config”页面。" }, "canvasError": { "cannotShowPreview": "无法显示预览", @@ -303,7 +319,8 @@ "doubleClick": "双击", "drag": "拖动", "editor": "编辑器", - "editSelectedShape": "编辑选中的形状 (文本、箭头或线条)", + "editLineArrowPoints": "", + "editText": "", "github": "提交问题", "howto": "帮助文档", "or": "或", diff --git a/src/locales/zh-HK.json b/src/locales/zh-HK.json index e87a0d3e1..bbf23f7f7 100644 --- a/src/locales/zh-HK.json +++ b/src/locales/zh-HK.json @@ -110,6 +110,7 @@ "increaseFontSize": "", "unbindText": "", "bindText": "", + "createContainerFromText": "", "link": { "edit": "", "create": "", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "", "importLibraryError": "", "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "" + "collabSaveFailed_sizeExceeded": "", + "brave_measure_text_error": { + "start": "", + "aggressive_block_fingerprint": "", + "setting_enabled": "", + "break": "", + "text_elements": "", + "in_your_drawings": "", + "strongly_recommend": "", + "steps": "", + "how": "", + "disable_setting": "", + "issue": "", + "write": "", + "discord": "" + } }, "toolBar": { "selection": "", @@ -303,7 +319,8 @@ "doubleClick": "", "drag": "", "editor": "", - "editSelectedShape": "", + "editLineArrowPoints": "", + "editText": "", "github": "", "howto": "", "or": "", diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 3293fad4a..f4462842c 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -110,6 +110,7 @@ "increaseFontSize": "放大文字", "unbindText": "取消綁定文字", "bindText": "結合文字至容器", + "createContainerFromText": "將文字包於容器中", "link": { "edit": "編輯連結", "create": "建立連結", @@ -204,7 +205,22 @@ "cannotResolveCollabServer": "無法連結至 collab 伺服器。請重新整理後再試一次。", "importLibraryError": "無法載入資料庫", "collabSaveFailed": "無法儲存至後端資料庫。若此問題持續發生,請將檔案儲存於本機以確保資料不會遺失。", - "collabSaveFailed_sizeExceeded": "無法儲存至後端資料庫,可能的原因為畫布尺寸過大。請將檔案儲存於本機以確保資料不會遺失。" + "collabSaveFailed_sizeExceeded": "無法儲存至後端資料庫,可能的原因為畫布尺寸過大。請將檔案儲存於本機以確保資料不會遺失。", + "brave_measure_text_error": { + "start": "您似乎正在使用 Brave 瀏覽器並且將", + "aggressive_block_fingerprint": "\"Aggressively Block Fingerprinting\" 設定", + "setting_enabled": "設為開啟", + "break": "這可能導致破壞", + "text_elements": "文字元素", + "in_your_drawings": "在您的繪圖中", + "strongly_recommend": "我們強烈建議您關掉此設定。您可以參考", + "steps": "這些步驟", + "how": "來變更", + "disable_setting": " 若關閉此設定無法修正文字元素的顯示問題,請回報", + "issue": "問題", + "write": "至我們的 GitHub,或反應在我們的", + "discord": "Discord" + } }, "toolBar": { "selection": "選取", @@ -303,7 +319,8 @@ "doubleClick": "雙擊", "drag": "拖曳", "editor": "編輯器", - "editSelectedShape": "編輯選定的形狀(文字/箭號/線條)", + "editLineArrowPoints": "編輯線/箭頭控制點", + "editText": "編輯文字/增加標籤", "github": "發現異常?回報問題", "howto": "參照我們的說明", "or": "或", From f640ddc2aa1320e674c7d8aed06e78572bf61213 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Sun, 16 Apr 2023 17:22:16 +0200 Subject: [PATCH 028/451] fix: incorrectly duplicating items on paste/library insert (#6467 * fix: incorrectly duplicating items on paste/library insert * fix: deduplicate element ids on restore * tests --- src/components/App.tsx | 35 +++---- src/data/restore.ts | 7 ++ src/element/newElement.ts | 43 +++++---- .../regressionTests.test.tsx.snap | 12 +-- src/tests/helpers/api.ts | 5 +- src/tests/library.test.tsx | 94 +++++++++++++++++++ 6 files changed, 153 insertions(+), 43 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 1ebdc7713..be5561995 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -127,7 +127,11 @@ import { } from "../element/binding"; import { LinearElementEditor } from "../element/linearElementEditor"; import { mutateElement, newElementWith } from "../element/mutateElement"; -import { deepCopyElement, newFreeDrawElement } from "../element/newElement"; +import { + deepCopyElement, + duplicateElements, + newFreeDrawElement, +} from "../element/newElement"; import { hasBoundTextElement, isArrowElement, @@ -1625,35 +1629,22 @@ class App extends React.Component { const dx = x - elementsCenterX; const dy = y - elementsCenterY; - const groupIdMap = new Map(); const [gridX, gridY] = getGridPoint(dx, dy, this.state.gridSize); - const oldIdToDuplicatedId = new Map(); - const newElements = elements.map((element) => { - const newElement = duplicateElement( - this.state.editingGroupId, - groupIdMap, - element, - { + const newElements = duplicateElements( + elements.map((element) => { + return newElementWith(element, { x: element.x + gridX - minX, y: element.y + gridY - minY, - }, - ); - oldIdToDuplicatedId.set(element.id, newElement.id); - return newElement; - }); + }); + }), + ); - bindTextToShapeAfterDuplication(newElements, elements, oldIdToDuplicatedId); const nextElements = [ ...this.scene.getElementsIncludingDeleted(), ...newElements, ]; - fixBindingsAfterDuplication(nextElements, elements, oldIdToDuplicatedId); - - if (opts.files) { - this.files = { ...this.files, ...opts.files }; - } this.scene.replaceAllElements(nextElements); @@ -1664,6 +1655,10 @@ class App extends React.Component { } }); + if (opts.files) { + this.files = { ...this.files, ...opts.files }; + } + this.history.resumeRecording(); this.setState( diff --git a/src/data/restore.ts b/src/data/restore.ts index 2735d91d2..fcf5fa132 100644 --- a/src/data/restore.ts +++ b/src/data/restore.ts @@ -369,6 +369,9 @@ export const restoreElements = ( localElements: readonly ExcalidrawElement[] | null | undefined, opts?: { refreshDimensions?: boolean; repairBindings?: boolean } | undefined, ): ExcalidrawElement[] => { + // used to detect duplicate top-level element ids + const existingIds = new Set(); + const localElementsMap = localElements ? arrayToMap(localElements) : null; const restoredElements = (elements || []).reduce((elements, element) => { // filtering out selection, which is legacy, no longer kept in elements, @@ -383,6 +386,10 @@ export const restoreElements = ( if (localElement && localElement.version > migratedElement.version) { migratedElement = bumpVersion(migratedElement, localElement.version); } + if (existingIds.has(migratedElement.id)) { + migratedElement = { ...migratedElement, id: randomId() }; + } + existingIds.add(migratedElement.id); elements.push(migratedElement); } } diff --git a/src/element/newElement.ts b/src/element/newElement.ts index 72aa54684..e3b25e848 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -439,6 +439,29 @@ export const deepCopyElement = ( return _deepCopyElement(val); }; +/** + * utility wrapper to generate new id. In test env it reuses the old + postfix + * for test assertions. + */ +const regenerateId = ( + /** supply null if no previous id exists */ + previousId: string | null, +) => { + if (isTestEnv() && previousId) { + let nextId = `${previousId}_copy`; + // `window.h` may not be defined in some unit tests + if ( + window.h?.app + ?.getSceneElementsIncludingDeleted() + .find((el) => el.id === nextId) + ) { + nextId += "_copy"; + } + return nextId; + } + return randomId(); +}; + /** * Duplicate an element, often used in the alt-drag operation. * Note that this method has gotten a bit complicated since the @@ -461,19 +484,7 @@ export const duplicateElement = ( ): Readonly => { let copy = deepCopyElement(element); - if (isTestEnv()) { - copy.id = `${copy.id}_copy`; - // `window.h` may not be defined in some unit tests - if ( - window.h?.app - ?.getSceneElementsIncludingDeleted() - .find((el) => el.id === copy.id) - ) { - copy.id += "_copy"; - } - } else { - copy.id = randomId(); - } + copy.id = regenerateId(copy.id); copy.boundElements = null; copy.updated = getUpdatedTimestamp(); copy.seed = randomInteger(); @@ -482,7 +493,7 @@ export const duplicateElement = ( editingGroupId, (groupId) => { if (!groupIdMapForOperation.has(groupId)) { - groupIdMapForOperation.set(groupId, randomId()); + groupIdMapForOperation.set(groupId, regenerateId(groupId)); } return groupIdMapForOperation.get(groupId)!; }, @@ -520,7 +531,7 @@ export const duplicateElements = (elements: readonly ExcalidrawElement[]) => { // if we haven't migrated the element id, but an old element with the same // id exists, generate a new id for it and return it if (origElementsMap.has(id)) { - const newId = randomId(); + const newId = regenerateId(id); elementNewIdsMap.set(id, newId); return newId; } @@ -538,7 +549,7 @@ export const duplicateElements = (elements: readonly ExcalidrawElement[]) => { if (clonedElement.groupIds) { clonedElement.groupIds = clonedElement.groupIds.map((groupId) => { if (!groupNewIdsMap.has(groupId)) { - groupNewIdsMap.set(groupId, randomId()); + groupNewIdsMap.set(groupId, regenerateId(groupId)); } return groupNewIdsMap.get(groupId)!; }); diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index 35f9eb7c8..967a0cf69 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -13431,7 +13431,7 @@ Object { "boundElements": null, "fillStyle": "hachure", "groupIds": Array [ - "id6", + "id4_copy", ], "height": 10, "id": "id0_copy", @@ -13464,7 +13464,7 @@ Object { "boundElements": null, "fillStyle": "hachure", "groupIds": Array [ - "id6", + "id4_copy", ], "height": 10, "id": "id1_copy", @@ -13497,7 +13497,7 @@ Object { "boundElements": null, "fillStyle": "hachure", "groupIds": Array [ - "id6", + "id4_copy", ], "height": 10, "id": "id2_copy", @@ -13981,7 +13981,7 @@ Object { "boundElements": null, "fillStyle": "hachure", "groupIds": Array [ - "id6", + "id4_copy", ], "height": 10, "id": "id0_copy", @@ -14011,7 +14011,7 @@ Object { "boundElements": null, "fillStyle": "hachure", "groupIds": Array [ - "id6", + "id4_copy", ], "height": 10, "id": "id1_copy", @@ -14041,7 +14041,7 @@ Object { "boundElements": null, "fillStyle": "hachure", "groupIds": Array [ - "id6", + "id4_copy", ], "height": 10, "id": "id2_copy", diff --git a/src/tests/helpers/api.ts b/src/tests/helpers/api.ts index bc8bfc8a9..705180d6a 100644 --- a/src/tests/helpers/api.ts +++ b/src/tests/helpers/api.ts @@ -211,7 +211,10 @@ export class API { type, startArrowhead: null, endArrowhead: null, - points: rest.points ?? [], + points: rest.points ?? [ + [0, 0], + [100, 100], + ], }); break; case "image": diff --git a/src/tests/library.test.tsx b/src/tests/library.test.tsx index 6b3ff5dd7..86847aeee 100644 --- a/src/tests/library.test.tsx +++ b/src/tests/library.test.tsx @@ -72,6 +72,100 @@ describe("library", () => { }); }); + it("should regenerate ids but retain bindings on library insert", async () => { + const rectangle = API.createElement({ + id: "rectangle1", + type: "rectangle", + boundElements: [ + { type: "text", id: "text1" }, + { type: "arrow", id: "arrow1" }, + ], + }); + const text = API.createElement({ + id: "text1", + type: "text", + text: "ola", + containerId: "rectangle1", + }); + const arrow = API.createElement({ + id: "arrow1", + type: "arrow", + endBinding: { elementId: "rectangle1", focus: -1, gap: 0 }, + }); + + await API.drop( + new Blob( + [ + serializeLibraryAsJSON([ + { + id: "item1", + status: "published", + elements: [rectangle, text, arrow], + created: 1, + }, + ]), + ], + { + type: MIME_TYPES.excalidrawlib, + }, + ), + ); + + await waitFor(() => { + expect(h.elements).toEqual([ + expect.objectContaining({ + id: "rectangle1_copy", + boundElements: expect.arrayContaining([ + { type: "text", id: "text1_copy" }, + { type: "arrow", id: "arrow1_copy" }, + ]), + }), + expect.objectContaining({ + id: "text1_copy", + containerId: "rectangle1_copy", + }), + expect.objectContaining({ + id: "arrow1_copy", + endBinding: expect.objectContaining({ elementId: "rectangle1_copy" }), + }), + ]); + }); + }); + + it("should fix duplicate ids between items on insert", async () => { + // note, we're not testing for duplicate group ids and such because + // deduplication of that happens upstream in the library component + // which would be very hard to orchestrate in this test + + const elem1 = API.createElement({ + id: "elem1", + type: "rectangle", + }); + const item1: LibraryItem = { + id: "item1", + status: "published", + elements: [elem1], + created: 1, + }; + + await API.drop( + new Blob([serializeLibraryAsJSON([item1, item1])], { + type: MIME_TYPES.excalidrawlib, + }), + ); + + await waitFor(() => { + expect(h.elements).toEqual([ + expect.objectContaining({ + id: "elem1_copy", + }), + expect.objectContaining({ + id: expect.not.stringMatching(/^(elem1_copy|elem1)$/), + }), + ]); + }); + }); + it("inserting library item should revert to selection tool", async () => { UI.clickTool("rectangle"); expect(h.elements).toEqual([]); From c3e8ddaf580f395366ff1fded0c9592a4485c701 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Mon, 17 Apr 2023 11:41:27 +0200 Subject: [PATCH 029/451] fix: improperly cache-busting on canvas scale instead of zoom (#6473) --- src/renderer/renderElement.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index 486e52bdf..21de70cb9 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -88,6 +88,7 @@ export interface ExcalidrawElementWithCanvas { canvas: HTMLCanvasElement; theme: RenderConfig["theme"]; scale: number; + zoomValue: RenderConfig["zoom"]["value"]; canvasOffsetX: number; canvasOffsetY: number; boundTextElementVersion: number | null; @@ -202,6 +203,7 @@ const generateElementCanvas = ( canvas, theme: renderConfig.theme, scale, + zoomValue: zoom.value, canvasOffsetX, canvasOffsetY, boundTextElementVersion: getBoundTextElement(element)?.version || null, @@ -712,7 +714,7 @@ const generateElementWithCanvas = ( const prevElementWithCanvas = elementWithCanvasCache.get(element); const shouldRegenerateBecauseZoom = prevElementWithCanvas && - prevElementWithCanvas.scale !== zoom.value && + prevElementWithCanvas.zoomValue !== zoom.value && !renderConfig?.shouldCacheIgnoreZoom; const boundTextElementVersion = getBoundTextElement(element)?.version || null; From 21726e22cce04aa2d3bdac7f270e2748156ca40e Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 18 Apr 2023 18:42:48 +0530 Subject: [PATCH 030/451] fix: mark more props as optional for element (#6448) * fix: mark more props as optional for element * fix --- src/appState.ts | 17 +++++----- src/charts.ts | 18 +---------- src/components/App.tsx | 2 -- src/constants.ts | 23 ++++++++++++- src/element/newElement.ts | 68 +++++++++++++++++++++++++++------------ 5 files changed, 80 insertions(+), 48 deletions(-) diff --git a/src/appState.ts b/src/appState.ts index f02d5943c..6f4db7557 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -1,5 +1,6 @@ import oc from "open-color"; import { + DEFAULT_ELEMENT_PROPS, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_TEXT_ALIGN, @@ -23,18 +24,18 @@ export const getDefaultAppState = (): Omit< theme: THEME.LIGHT, collaborators: new Map(), currentChartType: "bar", - currentItemBackgroundColor: "transparent", + currentItemBackgroundColor: DEFAULT_ELEMENT_PROPS.backgroundColor, currentItemEndArrowhead: "arrow", - currentItemFillStyle: "hachure", + currentItemFillStyle: DEFAULT_ELEMENT_PROPS.fillStyle, currentItemFontFamily: DEFAULT_FONT_FAMILY, currentItemFontSize: DEFAULT_FONT_SIZE, - currentItemOpacity: 100, - currentItemRoughness: 1, + currentItemOpacity: DEFAULT_ELEMENT_PROPS.opacity, + currentItemRoughness: DEFAULT_ELEMENT_PROPS.roughness, currentItemStartArrowhead: null, - currentItemStrokeColor: oc.black, + currentItemStrokeColor: DEFAULT_ELEMENT_PROPS.strokeColor, currentItemRoundness: "round", - currentItemStrokeStyle: "solid", - currentItemStrokeWidth: 1, + currentItemStrokeStyle: DEFAULT_ELEMENT_PROPS.strokeStyle, + currentItemStrokeWidth: DEFAULT_ELEMENT_PROPS.strokeWidth, currentItemTextAlign: DEFAULT_TEXT_ALIGN, cursorButton: "up", draggingElement: null, @@ -44,7 +45,7 @@ export const getDefaultAppState = (): Omit< activeTool: { type: "selection", customType: null, - locked: false, + locked: DEFAULT_ELEMENT_PROPS.locked, lastActiveTool: null, }, penMode: false, diff --git a/src/charts.ts b/src/charts.ts index e8980db6c..c3b0950d1 100644 --- a/src/charts.ts +++ b/src/charts.ts @@ -1,10 +1,5 @@ import colors from "./colors"; -import { - DEFAULT_FONT_FAMILY, - DEFAULT_FONT_SIZE, - ENV, - VERTICAL_ALIGN, -} from "./constants"; +import { DEFAULT_FONT_SIZE, ENV } from "./constants"; import { newElement, newLinearElement, newTextElement } from "./element"; import { NonDeletedExcalidrawElement } from "./element/types"; import { randomId } from "./random"; @@ -166,17 +161,7 @@ const bgColors = colors.elementBackground.slice( // Put all the common properties here so when the whole chart is selected // the properties dialog shows the correct selected values const commonProps = { - fillStyle: "hachure", - fontFamily: DEFAULT_FONT_FAMILY, - fontSize: DEFAULT_FONT_SIZE, - opacity: 100, - roughness: 1, strokeColor: colors.elementStroke[0], - roundness: null, - strokeStyle: "solid", - strokeWidth: 1, - verticalAlign: VERTICAL_ALIGN.MIDDLE, - locked: false, } as const; const getChartDimentions = (spreadsheet: Spreadsheet) => { @@ -323,7 +308,6 @@ const chartBaseElements = ( x: x + chartWidth / 2, y: y - BAR_HEIGHT - BAR_GAP * 2 - DEFAULT_FONT_SIZE, roundness: null, - strokeStyle: "solid", textAlign: "center", }) : null; diff --git a/src/components/App.tsx b/src/components/App.tsx index be5561995..fcbcca873 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2732,7 +2732,6 @@ class App extends React.Component { strokeStyle: this.state.currentItemStrokeStyle, roughness: this.state.currentItemRoughness, opacity: this.state.currentItemOpacity, - roundness: null, text: "", fontSize, fontFamily, @@ -2744,7 +2743,6 @@ class App extends React.Component { : DEFAULT_VERTICAL_ALIGN, containerId: shouldBindToContainer ? container?.id : undefined, groupIds: container?.groupIds ?? [], - locked: false, lineHeight, }); diff --git a/src/constants.ts b/src/constants.ts index ef563e4a4..23fefa6e5 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,7 @@ import cssVariables from "./css/variables.module.scss"; import { AppProps } from "./types"; -import { FontFamilyValues } from "./element/types"; +import { ExcalidrawElement, FontFamilyValues } from "./element/types"; +import oc from "open-color"; export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform); export const isWindows = /^Win/.test(navigator.platform); @@ -254,3 +255,23 @@ export const ROUNDNESS = { /** key containt id of precedeing elemnt id we use in reconciliation during * collaboration */ export const PRECEDING_ELEMENT_KEY = "__precedingElement__"; + +export const DEFAULT_ELEMENT_PROPS: { + strokeColor: ExcalidrawElement["strokeColor"]; + backgroundColor: ExcalidrawElement["backgroundColor"]; + fillStyle: ExcalidrawElement["fillStyle"]; + strokeWidth: ExcalidrawElement["strokeWidth"]; + strokeStyle: ExcalidrawElement["strokeStyle"]; + roughness: ExcalidrawElement["roughness"]; + opacity: ExcalidrawElement["opacity"]; + locked: ExcalidrawElement["locked"]; +} = { + strokeColor: oc.black, + backgroundColor: "transparent", + fillStyle: "hachure", + strokeWidth: 1, + strokeStyle: "solid", + roughness: 1, + opacity: 100, + locked: false, +}; diff --git a/src/element/newElement.ts b/src/element/newElement.ts index e3b25e848..36c8cc0e0 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -36,7 +36,14 @@ import { getMaxContainerWidth, getDefaultLineHeight, } from "./textElement"; -import { VERTICAL_ALIGN } from "../constants"; +import { + DEFAULT_ELEMENT_PROPS, + DEFAULT_FONT_FAMILY, + DEFAULT_FONT_SIZE, + DEFAULT_TEXT_ALIGN, + DEFAULT_VERTICAL_ALIGN, + VERTICAL_ALIGN, +} from "../constants"; import { isArrowElement } from "./typeChecks"; import { MarkOptional, Merge, Mutable } from "../utility-types"; @@ -51,6 +58,15 @@ type ElementConstructorOpts = MarkOptional< | "version" | "versionNonce" | "link" + | "strokeStyle" + | "fillStyle" + | "strokeColor" + | "backgroundColor" + | "roughness" + | "strokeWidth" + | "roundness" + | "locked" + | "opacity" >; const _newElementBase = ( @@ -58,13 +74,13 @@ const _newElementBase = ( { x, y, - strokeColor, - backgroundColor, - fillStyle, - strokeWidth, - strokeStyle, - roughness, - opacity, + strokeColor = DEFAULT_ELEMENT_PROPS.strokeColor, + backgroundColor = DEFAULT_ELEMENT_PROPS.backgroundColor, + fillStyle = DEFAULT_ELEMENT_PROPS.fillStyle, + strokeWidth = DEFAULT_ELEMENT_PROPS.strokeWidth, + strokeStyle = DEFAULT_ELEMENT_PROPS.strokeStyle, + roughness = DEFAULT_ELEMENT_PROPS.roughness, + opacity = DEFAULT_ELEMENT_PROPS.opacity, width = 0, height = 0, angle = 0, @@ -72,7 +88,7 @@ const _newElementBase = ( roundness = null, boundElements = null, link = null, - locked, + locked = DEFAULT_ELEMENT_PROPS.locked, ...rest }: ElementConstructorOpts & Omit, "type">, ) => { @@ -138,27 +154,39 @@ const getTextElementPositionOffsets = ( export const newTextElement = ( opts: { text: string; - fontSize: number; - fontFamily: FontFamilyValues; - textAlign: TextAlign; - verticalAlign: VerticalAlign; + fontSize?: number; + fontFamily?: FontFamilyValues; + textAlign?: TextAlign; + verticalAlign?: VerticalAlign; containerId?: ExcalidrawTextContainer["id"]; lineHeight?: ExcalidrawTextElement["lineHeight"]; + strokeWidth?: ExcalidrawTextElement["strokeWidth"]; } & ElementConstructorOpts, ): NonDeleted => { - const lineHeight = opts.lineHeight || getDefaultLineHeight(opts.fontFamily); + const fontFamily = opts.fontFamily || DEFAULT_FONT_FAMILY; + const fontSize = opts.fontSize || DEFAULT_FONT_SIZE; + const lineHeight = opts.lineHeight || getDefaultLineHeight(fontFamily); const text = normalizeText(opts.text); - const metrics = measureText(text, getFontString(opts), lineHeight); - const offsets = getTextElementPositionOffsets(opts, metrics); + const metrics = measureText( + text, + getFontString({ fontFamily, fontSize }), + lineHeight, + ); + const textAlign = opts.textAlign || DEFAULT_TEXT_ALIGN; + const verticalAlign = opts.verticalAlign || DEFAULT_VERTICAL_ALIGN; + const offsets = getTextElementPositionOffsets( + { textAlign, verticalAlign }, + metrics, + ); const textElement = newElementWith( { ..._newElementBase("text", opts), text, - fontSize: opts.fontSize, - fontFamily: opts.fontFamily, - textAlign: opts.textAlign, - verticalAlign: opts.verticalAlign, + fontSize, + fontFamily, + textAlign, + verticalAlign, x: opts.x - offsets.x, y: opts.y - offsets.y, width: metrics.width, From 801412bf6bd15b81403ec976a2089f2e303fff45 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 18 Apr 2023 18:50:25 +0530 Subject: [PATCH 031/451] fix: restore original container height when unbinding text which was binded via context menu (#6444) * fix: restore original container height when unbinding text which was binded via context menu * remove flag * comment --- src/actions/actionBoundText.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/actions/actionBoundText.tsx b/src/actions/actionBoundText.tsx index 3f240b5d8..830af3733 100644 --- a/src/actions/actionBoundText.tsx +++ b/src/actions/actionBoundText.tsx @@ -16,6 +16,7 @@ import { import { getOriginalContainerHeightFromCache, resetOriginalContainerCache, + updateOriginalContainerCache, } from "../element/textWysiwyg"; import { hasBoundTextElement, @@ -145,7 +146,11 @@ export const actionBindText = register({ id: textElement.id, }), }); + const originalContainerHeight = container.height; redrawTextBoundingBox(textElement, container); + // overwritting the cache with original container height so + // it can be restored when unbind + updateOriginalContainerCache(container.id, originalContainerHeight); return { elements: pushTextAboveContainer(elements, container, textElement), From 4d0d844e390e8b41d059f1fe646783c0465d1a41 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Tue, 18 Apr 2023 15:27:51 +0200 Subject: [PATCH 032/451] feat: constrain export dialog preview size (#6475) --- src/components/ImageExportDialog.tsx | 24 +++++++++++------------- src/packages/utils.ts | 6 +++++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/components/ImageExportDialog.tsx b/src/components/ImageExportDialog.tsx index fb2c1ec81..0e4eff365 100644 --- a/src/components/ImageExportDialog.tsx +++ b/src/components/ImageExportDialog.tsx @@ -4,7 +4,6 @@ import { canvasToBlob } from "../data/blob"; import { NonDeletedExcalidrawElement } from "../element/types"; import { t } from "../i18n"; import { getSelectedElements, isSomeElementSelected } from "../scene"; -import { exportToCanvas } from "../scene/export"; import { AppState, BinaryFiles } from "../types"; import { Dialog } from "./Dialog"; import { clipboard } from "./icons"; @@ -15,6 +14,7 @@ import { CheckboxItem } from "./CheckboxItem"; import { DEFAULT_EXPORT_PADDING, isFirefox } from "../constants"; import { nativeFileSystemSupported } from "../data/filesystem"; import { ActionManager } from "../actions/manager"; +import { exportToCanvas } from "../packages/utils"; const supportsContextFilters = "filter" in document.createElement("canvas").getContext("2d")!; @@ -83,7 +83,6 @@ const ImageExportModal = ({ const someElementIsSelected = isSomeElementSelected(elements, appState); const [exportSelected, setExportSelected] = useState(someElementIsSelected); const previewRef = useRef(null); - const { exportBackground, viewBackgroundColor } = appState; const [renderError, setRenderError] = useState(null); const exportedElements = exportSelected @@ -99,10 +98,16 @@ const ImageExportModal = ({ if (!previewNode) { return; } - exportToCanvas(exportedElements, appState, files, { - exportBackground, - viewBackgroundColor, + const maxWidth = previewNode.offsetWidth; + if (!maxWidth) { + return; + } + exportToCanvas({ + elements: exportedElements, + appState, + files, exportPadding, + maxWidthOrHeight: maxWidth, }) .then((canvas) => { setRenderError(null); @@ -116,14 +121,7 @@ const ImageExportModal = ({ console.error(error); setRenderError(error); }); - }, [ - appState, - files, - exportedElements, - exportBackground, - exportPadding, - viewBackgroundColor, - ]); + }, [appState, files, exportedElements, exportPadding]); return (
diff --git a/src/packages/utils.ts b/src/packages/utils.ts index 1fb6cd3d9..560fa13ca 100644 --- a/src/packages/utils.ts +++ b/src/packages/utils.ts @@ -79,7 +79,11 @@ export const exportToCanvas = ({ const max = Math.max(width, height); - const scale = maxWidthOrHeight / max; + // if content is less then maxWidthOrHeight, fallback on supplied scale + const scale = + maxWidthOrHeight < max + ? maxWidthOrHeight / max + : appState?.exportScale ?? 1; canvas.width = width * scale; canvas.height = height * scale; From 979312f779b675b9e6ad917ae0b04512fcfbd783 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 18 Apr 2023 19:44:14 +0530 Subject: [PATCH 033/451] fix: center align text when wrapped in container via context menu (#6480) * rename action to wrapTextInContainer * fix: center align text when wrapped in container via context menu * revert translation key * fix tests --- src/actions/actionBoundText.tsx | 5 +++-- src/actions/types.ts | 2 +- src/components/App.tsx | 4 ++-- src/element/textWysiwyg.test.tsx | 2 +- src/tests/__snapshots__/contextmenu.test.tsx.snap | 10 +++++----- src/tests/binding.test.tsx | 4 ++-- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/actions/actionBoundText.tsx b/src/actions/actionBoundText.tsx index 830af3733..658bdf8ce 100644 --- a/src/actions/actionBoundText.tsx +++ b/src/actions/actionBoundText.tsx @@ -196,8 +196,8 @@ const pushContainerBelowText = ( return updatedElements; }; -export const actionCreateContainerFromText = register({ - name: "createContainerFromText", +export const actionWrapTextInContainer = register({ + name: "wrapTextInContainer", contextItemLabel: "labels.createContainerFromText", trackEvent: { category: "element" }, predicate: (elements, appState) => { @@ -286,6 +286,7 @@ export const actionCreateContainerFromText = register({ containerId: container.id, verticalAlign: VERTICAL_ALIGN.MIDDLE, boundElements: null, + textAlign: TEXT_ALIGN.CENTER, }, false, ); diff --git a/src/actions/types.ts b/src/actions/types.ts index e46cd2ab8..b03e1053b 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -115,7 +115,7 @@ export type ActionName = | "toggleLinearEditor" | "toggleEraserTool" | "toggleHandTool" - | "createContainerFromText"; + | "wrapTextInContainer"; export type PanelComponentProps = { elements: readonly ExcalidrawElement[]; diff --git a/src/components/App.tsx b/src/components/App.tsx index fcbcca873..20def468a 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -295,7 +295,7 @@ import { } from "../actions/actionCanvas"; import { jotaiStore } from "../jotai"; import { activeConfirmDialogAtom } from "./ActiveConfirmDialog"; -import { actionCreateContainerFromText } from "../actions/actionBoundText"; +import { actionWrapTextInContainer } from "../actions/actionBoundText"; import BraveMeasureTextError from "./BraveMeasureTextError"; const deviceContextInitialValue = { @@ -6364,7 +6364,7 @@ class App extends React.Component { actionGroup, actionUnbindText, actionBindText, - actionCreateContainerFromText, + actionWrapTextInContainer, actionUngroup, CONTEXT_MENU_SEPARATOR, actionAddToLibrary, diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx index 4ae3f26f9..71c75c5a0 100644 --- a/src/element/textWysiwyg.test.tsx +++ b/src/element/textWysiwyg.test.tsx @@ -1506,7 +1506,7 @@ describe("textWysiwyg", () => { expect.objectContaining({ text: "Excalidraw is an opensource virtual collaborative whiteboard", verticalAlign: VERTICAL_ALIGN.MIDDLE, - textAlign: TEXT_ALIGN.LEFT, + textAlign: TEXT_ALIGN.CENTER, boundElements: null, }), ); diff --git a/src/tests/__snapshots__/contextmenu.test.tsx.snap b/src/tests/__snapshots__/contextmenu.test.tsx.snap index 18656edd1..c5b61e42f 100644 --- a/src/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/src/tests/__snapshots__/contextmenu.test.tsx.snap @@ -121,7 +121,7 @@ Object { }, Object { "contextItemLabel": "labels.createContainerFromText", - "name": "createContainerFromText", + "name": "wrapTextInContainer", "perform": [Function], "predicate": [Function], "trackEvent": Object { @@ -4518,7 +4518,7 @@ Object { }, Object { "contextItemLabel": "labels.createContainerFromText", - "name": "createContainerFromText", + "name": "wrapTextInContainer", "perform": [Function], "predicate": [Function], "trackEvent": Object { @@ -5068,7 +5068,7 @@ Object { }, Object { "contextItemLabel": "labels.createContainerFromText", - "name": "createContainerFromText", + "name": "wrapTextInContainer", "perform": [Function], "predicate": [Function], "trackEvent": Object { @@ -5917,7 +5917,7 @@ Object { }, Object { "contextItemLabel": "labels.createContainerFromText", - "name": "createContainerFromText", + "name": "wrapTextInContainer", "perform": [Function], "predicate": [Function], "trackEvent": Object { @@ -6263,7 +6263,7 @@ Object { }, Object { "contextItemLabel": "labels.createContainerFromText", - "name": "createContainerFromText", + "name": "wrapTextInContainer", "perform": [Function], "predicate": [Function], "trackEvent": Object { diff --git a/src/tests/binding.test.tsx b/src/tests/binding.test.tsx index c615eb925..07af36569 100644 --- a/src/tests/binding.test.tsx +++ b/src/tests/binding.test.tsx @@ -4,7 +4,7 @@ import { UI, Pointer, Keyboard } from "./helpers/ui"; import { getTransformHandles } from "../element/transformHandles"; import { API } from "./helpers/api"; import { KEYS } from "../keys"; -import { actionCreateContainerFromText } from "../actions/actionBoundText"; +import { actionWrapTextInContainer } from "../actions/actionBoundText"; const { h } = window; @@ -277,7 +277,7 @@ describe("element binding", () => { expect(h.state.selectedElementIds[text1.id]).toBe(true); - h.app.actionManager.executeAction(actionCreateContainerFromText); + h.app.actionManager.executeAction(actionWrapTextInContainer); // new text container will be placed before the text element const container = h.elements.at(-2)!; From c9c79646c535dbca2342c5f3de26c24c6aadce19 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 18 Apr 2023 20:48:30 +0530 Subject: [PATCH 034/451] =?UTF-8?q?docs:=20release=20@excalidraw/excalidra?= =?UTF-8?q?w@0.15.0=20=20=F0=9F=8E=89=20(#6481)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/excalidraw/CHANGELOG.md | 150 ++++++++++++++++++++++++++- src/packages/excalidraw/package.json | 2 +- 2 files changed, 150 insertions(+), 2 deletions(-) diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index c36883b8e..5143bda31 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -11,7 +11,7 @@ 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. --> -## Unreleased +## 0.15.0 (2023-04-18) ### Features @@ -37,6 +37,154 @@ For more details refer to the [docs](https://docs.excalidraw.com) - Exporting labelled arrows via export utils [#6443](https://github.com/excalidraw/excalidraw/pull/6443) +## Excalidraw Library + +**_This section lists the updates made to the excalidraw library and will not affect the integration._** + +### Features + +- Constrain export dialog preview size [#6475](https://github.com/excalidraw/excalidraw/pull/6475) + +- Zigzag fill easter egg [#6439](https://github.com/excalidraw/excalidraw/pull/6439) + +- Add container to multiple text elements [#6428](https://github.com/excalidraw/excalidraw/pull/6428) + +- Starting migration from GA to Matomo for better privacy [#6398](https://github.com/excalidraw/excalidraw/pull/6398) + +- Add line height attribute to text element [#6360](https://github.com/excalidraw/excalidraw/pull/6360) + +- Add thai lang support [#6314](https://github.com/excalidraw/excalidraw/pull/6314) + +- Create bound container from text [#6301](https://github.com/excalidraw/excalidraw/pull/6301) + +- Improve text measurements in bound containers [#6187](https://github.com/excalidraw/excalidraw/pull/6187) + +- Bind text to container if double clicked on filled shape or stroke [#6250](https://github.com/excalidraw/excalidraw/pull/6250) + +- Make repair and refreshDimensions configurable in restoreElements [#6238](https://github.com/excalidraw/excalidraw/pull/6238) + +- Show error message when not connected to internet while collabo… [#6165](https://github.com/excalidraw/excalidraw/pull/6165) + +- Shortcut for clearCanvas confirmDialog [#6114](https://github.com/excalidraw/excalidraw/pull/6114) + +- Disable canvas smoothing (antialiasing) for right-angled elements [#6186](https://github.com/excalidraw/excalidraw/pull/6186)Co-authored-by: Ignacio Cuadra <67276174+ignacio-cuadra@users.noreply.github.com> + +### Fixes + +- Center align text when wrapped in container via context menu [#6480](https://github.com/excalidraw/excalidraw/pull/6480) + +- Restore original container height when unbinding text which was binded via context menu [#6444](https://github.com/excalidraw/excalidraw/pull/6444) + +- Mark more props as optional for element [#6448](https://github.com/excalidraw/excalidraw/pull/6448) + +- Improperly cache-busting on canvas scale instead of zoom [#6473](https://github.com/excalidraw/excalidraw/pull/6473) + +- Incorrectly duplicating items on paste/library insert [#6467](https://github.com/excalidraw/excalidraw/pull/6467) + +- Library ids cross-contamination on multiple insert [#6466](https://github.com/excalidraw/excalidraw/pull/6466) + +- Color picker keyboard handling not working [#6464](https://github.com/excalidraw/excalidraw/pull/6464) + +- Abort freedraw line if second touch is detected [#6440](https://github.com/excalidraw/excalidraw/pull/6440) + +- Utils leaking Scene state [#6461](https://github.com/excalidraw/excalidraw/pull/6461) + +- Split "Edit selected shape" shortcut [#6457](https://github.com/excalidraw/excalidraw/pull/6457) + +- Center align text when bind to container via context menu [#6451](https://github.com/excalidraw/excalidraw/pull/6451) + +- Update coords when text unbinded from its container [#6445](https://github.com/excalidraw/excalidraw/pull/6445) + +- Autoredirect to plus in prod only [#6446](https://github.com/excalidraw/excalidraw/pull/6446) + +- Fixing popover overflow on small screen [#6433](https://github.com/excalidraw/excalidraw/pull/6433) + +- Introduce baseline to fix the layout shift when switching to text editor [#6397](https://github.com/excalidraw/excalidraw/pull/6397) + +- Don't refresh dimensions for deleted text elements [#6438](https://github.com/excalidraw/excalidraw/pull/6438) + +- Element vanishes when zoomed in [#6417](https://github.com/excalidraw/excalidraw/pull/6417) + +- Don't jump text to end when out of viewport in safari [#6416](https://github.com/excalidraw/excalidraw/pull/6416) + +- GetDefaultLineHeight should return default font family line height for unknown font [#6399](https://github.com/excalidraw/excalidraw/pull/6399) + +- Revert use `ideographic` textBaseline to improve layout shift when editing text" [#6400](https://github.com/excalidraw/excalidraw/pull/6400) + +- Call stack size exceeded when paste large text [#6373](https://github.com/excalidraw/excalidraw/pull/6373) (#6396) + +- Use `ideographic` textBaseline to improve layout shift when editing text [#6384](https://github.com/excalidraw/excalidraw/pull/6384) + +- Chrome crashing when embedding scene on chrome arm [#6383](https://github.com/excalidraw/excalidraw/pull/6383) + +- Division by zero in findFocusPointForEllipse leads to infinite loop in wrapText freezing Excalidraw [#6377](https://github.com/excalidraw/excalidraw/pull/6377) + +- Containerizing text incorrectly updates arrow bindings [#6369](https://github.com/excalidraw/excalidraw/pull/6369) + +- Ensure export preview is centered [#6337](https://github.com/excalidraw/excalidraw/pull/6337) + +- Hide text align for labelled arrows [#6339](https://github.com/excalidraw/excalidraw/pull/6339) + +- Refresh dimensions when elements loaded from shareable link and blob [#6333](https://github.com/excalidraw/excalidraw/pull/6333) + +- Show error message when measureText API breaks in brave [#6336](https://github.com/excalidraw/excalidraw/pull/6336) + +- Add an offset of 0.5px for text editor in containers [#6328](https://github.com/excalidraw/excalidraw/pull/6328) + +- Move utility types out of `.d.ts` file to fix exported declaration files [#6315](https://github.com/excalidraw/excalidraw/pull/6315) + +- More jotai scopes missing [#6313](https://github.com/excalidraw/excalidraw/pull/6313) + +- Provide HelpButton title prop [#6209](https://github.com/excalidraw/excalidraw/pull/6209) + +- Respect text align when wrapping in a container [#6310](https://github.com/excalidraw/excalidraw/pull/6310) + +- Compute bounding box correctly for text element when multiple element resizing [#6307](https://github.com/excalidraw/excalidraw/pull/6307) + +- Use jotai scope for editor-specific atoms [#6308](https://github.com/excalidraw/excalidraw/pull/6308) + +- Consider arrow for bound text element [#6297](https://github.com/excalidraw/excalidraw/pull/6297) + +- Text never goes beyond max width for unbound text elements [#6288](https://github.com/excalidraw/excalidraw/pull/6288) + +- Svg text baseline [#6285](https://github.com/excalidraw/excalidraw/pull/6273) + +- Compute container height from bound text correctly [#6273](https://github.com/excalidraw/excalidraw/pull/6273) + +- Fit mobile toolbar and make scrollable [#6270](https://github.com/excalidraw/excalidraw/pull/6270) + +- Indenting via `tab` clashing with IME compositor [#6258](https://github.com/excalidraw/excalidraw/pull/6258) + +- Improve text wrapping inside rhombus and more fixes [#6265](https://github.com/excalidraw/excalidraw/pull/6265) + +- Improve text wrapping in ellipse and alignment [#6172](https://github.com/excalidraw/excalidraw/pull/6172) + +- Don't allow blank space in collab name [#6211](https://github.com/excalidraw/excalidraw/pull/6211) + +- Docker build architecture:linux/amd64 error occur on linux/arm64 instance [#6197](https://github.com/excalidraw/excalidraw/pull/6197) + +- Sort bound text elements to fix text duplication z-index error [#5130](https://github.com/excalidraw/excalidraw/pull/5130) + +- Hide welcome screen on mobile once user interacts [#6185](https://github.com/excalidraw/excalidraw/pull/6185) + +- Edit link in docs [#6182](https://github.com/excalidraw/excalidraw/pull/6182) + +### Refactor + +- Inline `SingleLibraryItem` into `PublishLibrary` [#6462](https://github.com/excalidraw/excalidraw/pull/6462) + +- Make the example React app reusable without duplication [#6188](https://github.com/excalidraw/excalidraw/pull/6188) + +### Performance + +- Break early if the line width <= max width of the container [#6347](https://github.com/excalidraw/excalidraw/pull/6347) + +### Build + +- Move TS and types to devDependencies [#6346](https://github.com/excalidraw/excalidraw/pull/6346) + +--- + ## 0.14.2 (2023-02-01) ### Features diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index be4e61d27..2351ee6a5 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -1,6 +1,6 @@ { "name": "@excalidraw/excalidraw", - "version": "0.14.2", + "version": "0.15.0", "main": "main.js", "types": "types/packages/excalidraw/index.d.ts", "files": [ From 1d0653ce50cfc56b92235bf793cfa638f39144c4 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 18 Apr 2023 21:03:17 +0530 Subject: [PATCH 035/451] docs: update docs for next version (#6251) * update docs for opts param inr estore utils * docs: add docs for `useI18n` hook (#6269) Co-authored-by: Aakansha Doshi * upgrade excal --------- Co-authored-by: David Luzar --- .../excalidraw/api/utils/restore.mdx | 28 +++++++++--- .../excalidraw/api/utils/utils-intro.md | 44 +++++++++++++++++++ dev-docs/package.json | 2 +- dev-docs/src/theme/ReactLiveScope/index.js | 1 + dev-docs/yarn.lock | 8 ++-- 5 files changed, 73 insertions(+), 10 deletions(-) diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/utils/restore.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/utils/restore.mdx index 198626eec..665a1ef9f 100644 --- a/dev-docs/docs/@excalidraw/excalidraw/api/utils/restore.mdx +++ b/dev-docs/docs/@excalidraw/excalidraw/api/utils/restore.mdx @@ -31,10 +31,29 @@ You can pass `null` / `undefined` if not applicable. restoreElements( elements: ImportedDataState["elements"],
  localElements: ExcalidrawElement[] | null | undefined): ExcalidrawElement[],
  - refreshDimensions?: boolean
+ opts: { refreshDimensions?: boolean, repairBindings?: boolean }
) +| Prop | Type | Description | +| ---- | ---- | ---- | +| `elements` | ImportedDataState["elements"] | The `elements` to be restored | +| [`localElements`](#localelements) | ExcalidrawElement[] | null | undefined | When `localElements` are supplied, they are used to ensure that existing restored elements reuse `version` (and increment it), and regenerate `versionNonce`. | +| [`opts`](#opts) | `Object` | The extra optional parameter to configure restored elements + +#### localElements + +When `localElements` are supplied, they are used to ensure that existing restored elements reuse `version` (and increment it), and regenerate `versionNonce`. +Use this when you `import` elements which may already be present in the scene to ensure that you do not disregard the newly imported elements if you're using element version to detect the update + +#### opts +The extra optional parameter to configure restored elements. It has the following attributes + +| Prop | Type | Description| +| --- | --- | ------| +| `refreshDimensions` | `boolean` | Indicates whether we should also `recalculate` text element dimensions. Since this is a potentially costly operation, you may want to disable it if you restore elements in tight loops, such as during collaboration. | +| `repairBindings` |`boolean` | Indicates whether the `bindings` for the elements should be repaired. This is to make sure there are no containers with non existent bound text element id and no bound text elements with non existent container id. | + **_How to use_** ```js @@ -43,9 +62,6 @@ import { restoreElements } from "@excalidraw/excalidraw"; This function will make sure all properties of element is correctly set and if any attribute is missing, it will be set to its default value. -When `localElements` are supplied, they are used to ensure that existing restored elements reuse `version` (and increment it), and regenerate `versionNonce`. -Use this when you import elements which may already be present in the scene to ensure that you do not disregard the newly imported elements if you're using element version to detect the updates. - Parameter `refreshDimensions` indicates whether we should also `recalculate` text element dimensions. Defaults to `false`. Since this is a potentially costly operation, you may want to disable it if you restore elements in tight loops, such as during collaboration. ### restore @@ -56,7 +72,9 @@ Parameter `refreshDimensions` indicates whether we should also `recalculate` tex restore( data: ImportedDataState,
  localAppState: Partial<AppState> | null | undefined,
  - localElements: ExcalidrawElement[] | null | undefined
): DataState + localElements: ExcalidrawElement[] | null | undefined
): DataState
+ opts: { refreshDimensions?: boolean, repairBindings?: boolean }
+ ) diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/utils/utils-intro.md b/dev-docs/docs/@excalidraw/excalidraw/api/utils/utils-intro.md index c21592382..4d2745c09 100644 --- a/dev-docs/docs/@excalidraw/excalidraw/api/utils/utils-intro.md +++ b/dev-docs/docs/@excalidraw/excalidraw/api/utils/utils-intro.md @@ -339,3 +339,47 @@ The `device` has the following `attributes` | `isMobile` | `boolean` | Set to `true` when the device is `mobile` | | `isTouchScreen` | `boolean` | Set to `true` for `touch` devices | | `canDeviceFitSidebar` | `boolean` | Implies whether there is enough space to fit the `sidebar` | + +### i18n + +To help with localization, we export the following. + +| name | type | +| --- | --- | +| `defaultLang` | `string` | +| `languages` | [`Language[]`](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L15) | +| `useI18n` | [`() => { langCode, t }`](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L15) | + +```js +import { defaultLang, languages, useI18n } from "@excalidraw/excalidraw"; +``` + +#### defaultLang + +Default language code, `en`. + +#### languages + +List of supported language codes. You can pass any of these to `Excalidraw`'s [`langCode` prop](/docs/@excalidraw/excalidraw/api/props/#langcode). + +#### useI18n + +A hook that returns the current language code and translation helper function. You can use this to translate strings in the components you render as children of ``. + +```jsx live +function App() { + const { t } = useI18n(); + return ( +
+ + + +
+ ); +} +``` diff --git a/dev-docs/package.json b/dev-docs/package.json index dd3c45872..1e8745910 100644 --- a/dev-docs/package.json +++ b/dev-docs/package.json @@ -18,7 +18,7 @@ "@docusaurus/core": "2.2.0", "@docusaurus/preset-classic": "2.2.0", "@docusaurus/theme-live-codeblock": "2.2.0", - "@excalidraw/excalidraw": "0.14.2", + "@excalidraw/excalidraw": "0.15.0", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "docusaurus-plugin-sass": "0.2.3", diff --git a/dev-docs/src/theme/ReactLiveScope/index.js b/dev-docs/src/theme/ReactLiveScope/index.js index a282ad6f0..e5263e1db 100644 --- a/dev-docs/src/theme/ReactLiveScope/index.js +++ b/dev-docs/src/theme/ReactLiveScope/index.js @@ -24,6 +24,7 @@ const ExcalidrawScope = { Sidebar: ExcalidrawComp.Sidebar, exportToCanvas: ExcalidrawComp.exportToCanvas, initialData, + useI18n: ExcalidrawComp.useI18n, }; export default ExcalidrawScope; diff --git a/dev-docs/yarn.lock b/dev-docs/yarn.lock index 041f39b55..ee3d50cbf 100644 --- a/dev-docs/yarn.lock +++ b/dev-docs/yarn.lock @@ -1631,10 +1631,10 @@ url-loader "^4.1.1" webpack "^5.73.0" -"@excalidraw/excalidraw@0.14.2": - version "0.14.2" - resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.14.2.tgz#150cb4b7a1bf0d11cd64295936c930e7e0db8375" - integrity sha512-8LdjpTBWEK5waDWB7Bt/G9YBI4j0OxkstUhvaDGz7dwQGfzF6FW5CXBoYHNEoX0qmb+Fg/NPOlZ7FrKsrSVCqg== +"@excalidraw/excalidraw@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.15.0.tgz#47170de8d3ff006e9d09dfede2815682b0d4485b" + integrity sha512-PJmh1VcuRHG4l+Zgt9qhezxrJ16tYCZFZ8if5IEfmTL9A/7c5mXxY/qrPTqiGlVC7jYs+ciePXQ0YUDzfOfbzw== "@hapi/hoek@^9.0.0": version "9.3.0" From 89304c9f66ac9949edb47d254ae3d99602b2dff4 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 18 Apr 2023 21:23:47 +0530 Subject: [PATCH 036/451] fix: add readme back to npm package which was mistakenly removed (#6484) * fix: remove update readme script from release * update docs * remove * fix --- scripts/release.js | 20 -------------------- src/packages/excalidraw/CHANGELOG.md | 6 ++++++ 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/scripts/release.js b/scripts/release.js index 986eadc2a..24ac89c6b 100644 --- a/scripts/release.js +++ b/scripts/release.js @@ -1,22 +1,9 @@ -const fs = require("fs"); const { execSync } = require("child_process"); const excalidrawDir = `${__dirname}/../src/packages/excalidraw`; const excalidrawPackage = `${excalidrawDir}/package.json`; const pkg = require(excalidrawPackage); -const originalReadMe = fs.readFileSync(`${excalidrawDir}/README.md`, "utf8"); - -const updateReadme = () => { - const excalidrawIndex = originalReadMe.indexOf("### Excalidraw"); - - // remove note for stable readme - const data = originalReadMe.slice(excalidrawIndex); - - // update readme - fs.writeFileSync(`${excalidrawDir}/README.md`, data, "utf8"); -}; - const publish = () => { try { execSync(`yarn --frozen-lockfile`); @@ -30,15 +17,8 @@ const publish = () => { }; const release = () => { - updateReadme(); - console.info("Note for stable readme removed"); - publish(); console.info(`Published ${pkg.version}!`); - - // revert readme after release - fs.writeFileSync(`${excalidrawDir}/README.md`, originalReadMe, "utf8"); - console.info("Readme reverted"); }; release(); diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index 5143bda31..b2ac3a682 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -11,6 +11,12 @@ 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. --> +## Unreleased + +### Docs + +- Add the readme back to the package which was mistakenly removed [#6484](https://github.com/excalidraw/excalidraw/pull/6484) + ## 0.15.0 (2023-04-18) ### Features From b64beaf5ba42ab55302fb9f5b752b06b28c0c213 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 18 Apr 2023 21:32:33 +0530 Subject: [PATCH 037/451] =?UTF-8?q?docs:=20release=20@excalidraw/excalidra?= =?UTF-8?q?w@0.15.1=20=20=F0=9F=8E=89=20(#6485)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/excalidraw/CHANGELOG.md | 8 +++++++- src/packages/excalidraw/package.json | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index b2ac3a682..f285349f0 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -11,12 +11,18 @@ 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. --> -## Unreleased +## 0.15.1 (2023-04-18) ### Docs - Add the readme back to the package which was mistakenly removed [#6484](https://github.com/excalidraw/excalidraw/pull/6484) +## Excalidraw Library + +**_This section lists the updates made to the excalidraw library and will not affect the integration._** + +--- + ## 0.15.0 (2023-04-18) ### Features diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index 2351ee6a5..a59837454 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -1,6 +1,6 @@ { "name": "@excalidraw/excalidraw", - "version": "0.15.0", + "version": "0.15.1", "main": "main.js", "types": "types/packages/excalidraw/index.d.ts", "files": [ From ff3c2e5a160d2982d48657091f1fbcaacf82a6e2 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 18 Apr 2023 21:52:08 +0530 Subject: [PATCH 038/451] docs: fix docs link in readme (#6486) * docs: fix docs link in readme * update changelog --- src/packages/excalidraw/CHANGELOG.md | 6 ++++++ src/packages/excalidraw/README.md | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index f285349f0..e69f05d0a 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -11,6 +11,12 @@ 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. --> +## Unreleased + +### Docs + +- Fix docs link in readme [#6486](https://github.com/excalidraw/excalidraw/pull/6486) + ## 0.15.1 (2023-04-18) ### Docs diff --git a/src/packages/excalidraw/README.md b/src/packages/excalidraw/README.md index eaeef4b0c..d650885df 100644 --- a/src/packages/excalidraw/README.md +++ b/src/packages/excalidraw/README.md @@ -38,8 +38,8 @@ Excalidraw takes _100%_ of `width` and `height` of the containing block so make ## Integration -Head over to the [docs](https://docs.excalidraw.com/docs/package/integration) +Head over to the [docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/integration) ## API -Head over to the [docs](https://docs.excalidraw.com/docs/package/api) +Head over to the [docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api) From 98a77d7426ea3de9c26418f35ef9c6389f3e1d25 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Wed, 19 Apr 2023 17:02:20 +0530 Subject: [PATCH 039/451] chore: show bounding box only when flag is true (#6490) --- src/renderer/renderElement.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index 21de70cb9..f85c83a6b 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -864,7 +864,8 @@ const drawElementFromCanvas = ( ); if ( - process.env.REACT_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX && + process.env.REACT_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX === + "true" && hasBoundTextElement(element) ) { const coords = getContainerCoords(element); From eea30da05a5847e28df7f56051575c5daf7ae49e Mon Sep 17 00:00:00 2001 From: David Luzar Date: Wed, 19 Apr 2023 16:23:24 +0200 Subject: [PATCH 040/451] fix: incorrect background fill button active state (#6491) --- src/actions/actionProperties.tsx | 12 +++++++----- src/locales/en.json | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index ed714816b..382e964b9 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -84,7 +84,7 @@ import { isSomeElementSelected, } from "../scene"; import { hasStrokeColor } from "../scene/comparisons"; -import { arrayToMap } from "../utils"; +import { arrayToMap, getShortcutKey } from "../utils"; import { register } from "./register"; const FONT_SIZE_RELATIVE_INCREASE_STEP = 0.1; @@ -314,9 +314,9 @@ export const actionChangeFillStyle = register({ }, PanelComponent: ({ elements, appState, updateData }) => { const selectedElements = getSelectedElements(elements, appState); - const allElementsZigZag = selectedElements.every( - (el) => el.fillStyle === "zigzag", - ); + const allElementsZigZag = + selectedElements.length > 0 && + selectedElements.every((el) => el.fillStyle === "zigzag"); return (
@@ -326,7 +326,9 @@ export const actionChangeFillStyle = register({ options={[ { value: "hachure", - text: t("labels.hachure"), + text: `${ + allElementsZigZag ? t("labels.zigzag") : t("labels.hachure") + } (${getShortcutKey("Alt-Click")})`, icon: allElementsZigZag ? FillZigZagIcon : FillHachureIcon, active: allElementsZigZag ? true : undefined, }, diff --git a/src/locales/en.json b/src/locales/en.json index 8752d415a..7e250a800 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -54,6 +54,7 @@ "veryLarge": "Very large", "solid": "Solid", "hachure": "Hachure", + "zigzag": "Zigzag", "crossHatch": "Cross-hatch", "thin": "Thin", "bold": "Bold", From 404a79e241e4aa2eda287513e9cef497e40da832 Mon Sep 17 00:00:00 2001 From: Max Kovalenko Date: Wed, 19 Apr 2023 13:18:03 -0400 Subject: [PATCH 041/451] chore: typo (collab) - reconciliation.ts (#6447) --- src/excalidraw-app/collab/reconciliation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/excalidraw-app/collab/reconciliation.ts b/src/excalidraw-app/collab/reconciliation.ts index 76b6f052a..3f50bc358 100644 --- a/src/excalidraw-app/collab/reconciliation.ts +++ b/src/excalidraw-app/collab/reconciliation.ts @@ -65,7 +65,7 @@ export const reconcileElements = ( // Mark duplicate for removal as it'll be replaced with the remote element if (local) { - // Unless the ramote and local elements are the same element in which case + // Unless the remote and local elements are the same element in which case // we need to keep it as we'd otherwise discard it from the resulting // array. if (local[0] === remoteElement) { From 5ddb28d37830174798ad3a4e7b1ce319ea8b1cfb Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Thu, 20 Apr 2023 11:10:46 +0530 Subject: [PATCH 042/451] fix: support breaking words containing hyphen - (#6014) * fix: support breaking words containing hyphen - * fix * add spec * fix * fix * fix * fix and add spec * improve code and add more tests --- src/element/textElement.test.ts | 51 +++++++++++++++++++++++++++++++++ src/element/textElement.ts | 47 ++++++++++++++++++++++++------ 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/src/element/textElement.test.ts b/src/element/textElement.test.ts index 106ed7bea..f83eafd1b 100644 --- a/src/element/textElement.test.ts +++ b/src/element/textElement.test.ts @@ -9,6 +9,7 @@ import { detectLineHeight, getLineHeightInPx, getDefaultLineHeight, + parseTokens, } from "./textElement"; import { FontString } from "./types"; @@ -183,6 +184,56 @@ now`, expect(wrapText(text, font, -1)).toEqual(text); expect(wrapText(text, font, Infinity)).toEqual(text); }); + + it("should wrap the text correctly when text contains hyphen", () => { + let text = + "Wikipedia is hosted by Wikimedia- Foundation, a non-profit organization that also hosts a range-of other projects"; + const res = wrapText(text, font, 110); + expect(res).toBe( + `Wikipedia \nis hosted \nby \nWikimedia-\nFoundation,\na non-\nprofit \norganizati\non that \nalso hosts\na range-of\nother \nprojects`, + ); + + text = "Hello thereusing-now"; + expect(wrapText(text, font, 100)).toEqual("Hello \nthereusin\ng-now"); + }); +}); + +describe("Test parseTokens", () => { + it("should split into tokens correctly", () => { + let text = "Excalidraw is a virtual collaborative whiteboard"; + expect(parseTokens(text)).toEqual([ + "Excalidraw", + "is", + "a", + "virtual", + "collaborative", + "whiteboard", + ]); + + text = + "Wikipedia is hosted by Wikimedia- Foundation, a non-profit organization that also hosts a range-of other projects"; + expect(parseTokens(text)).toEqual([ + "Wikipedia", + "is", + "hosted", + "by", + "Wikimedia-", + "", + "Foundation,", + "a", + "non-", + "profit", + "organization", + "that", + "also", + "hosts", + "a", + "range-", + "of", + "other", + "projects", + ]); + }); }); describe("Test measureText", () => { diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 38da5df5a..f01ba3e1b 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -419,6 +419,24 @@ export const getTextHeight = ( return getLineHeightInPx(fontSize, lineHeight) * lineCount; }; +export const parseTokens = (text: string) => { + // Splitting words containing "-" as those are treated as separate words + // by css wrapping algorithm eg non-profit => non-, profit + const words = text.split("-"); + if (words.length > 1) { + // non-proft org => ['non-', 'profit org'] + words.forEach((word, index) => { + if (index !== words.length - 1) { + words[index] = word += "-"; + } + }); + } + // Joining the words with space and splitting them again with space to get the + // final list of tokens + // ['non-', 'profit org'] =>,'non- proft org' => ['non-','profit','org'] + return words.join(" ").split(" "); +}; + export const wrapText = (text: string, font: FontString, maxWidth: number) => { // if maxWidth is not finite or NaN which can happen in case of bugs in // computation, we need to make sure we don't continue as we'll end up @@ -444,17 +462,16 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { currentLine = ""; currentLineWidthTillNow = 0; }; - originalLines.forEach((originalLine) => { const currentLineWidth = getTextWidth(originalLine, font); - //Push the line if its <= maxWidth + // Push the line if its <= maxWidth if (currentLineWidth <= maxWidth) { lines.push(originalLine); return; // continue } - const words = originalLine.split(" "); + const words = parseTokens(originalLine); resetParams(); let index = 0; @@ -472,6 +489,7 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { else if (currentWordWidth > maxWidth) { // push current line since the current word exceeds the max width // so will be appended in next line + push(currentLine); resetParams(); @@ -492,15 +510,15 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { currentLine += currentChar; } } - // push current line if appending space exceeds max width if (currentLineWidthTillNow + spaceWidth >= maxWidth) { push(currentLine); resetParams(); - } else { // space needs to be appended before next word // as currentLine contains chars which couldn't be appended - // to previous line + // to previous line unless the line ends with hyphen to sync + // with css word-wrap + } else if (!currentLine.endsWith("-")) { currentLine += " "; currentLineWidthTillNow += spaceWidth; } @@ -518,12 +536,23 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { break; } index++; - currentLine += `${word} `; + + // if word ends with "-" then we don't need to add space + // to sync with css word-wrap + const shouldAppendSpace = !word.endsWith("-"); + currentLine += word; + + if (shouldAppendSpace) { + currentLine += " "; + } // Push the word if appending space exceeds max width if (currentLineWidthTillNow + spaceWidth >= maxWidth) { - const word = currentLine.slice(0, -1); - push(word); + if (shouldAppendSpace) { + lines.push(currentLine.slice(0, -1)); + } else { + lines.push(currentLine); + } resetParams(); break; } From 851b9b7aecb97bee6a55da669f4a431a3fca733c Mon Sep 17 00:00:00 2001 From: siddhant <30566406+siddhant1@users.noreply.github.com> Date: Thu, 20 Apr 2023 16:34:39 +0530 Subject: [PATCH 043/451] fix: rotate the text element when binding to a rotated container (#6477) * Updated logic to update the bound child angle from the parent * update angle when generating text element * add test * remove * fix --------- Co-authored-by: Aakansha Doshi --- src/components/App.tsx | 1 + src/element/textWysiwyg.test.tsx | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/components/App.tsx b/src/components/App.tsx index 20def468a..413a130d8 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2744,6 +2744,7 @@ class App extends React.Component { containerId: shouldBindToContainer ? container?.id : undefined, groupIds: container?.groupIds ?? [], lineHeight, + angle: container?.angle ?? 0, }); if (!existingTextElement && shouldBindToContainer && container) { diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx index 71c75c5a0..f3c75db8b 100644 --- a/src/element/textWysiwyg.test.tsx +++ b/src/element/textWysiwyg.test.tsx @@ -526,6 +526,36 @@ describe("textWysiwyg", () => { ]); }); + it("should set the text element angle to same as container angle when binding to rotated container", async () => { + const rectangle = API.createElement({ + type: "rectangle", + width: 90, + height: 75, + angle: 45, + }); + h.elements = [rectangle]; + mouse.doubleClickAt(rectangle.x + 10, rectangle.y + 10); + const text = h.elements[1] as ExcalidrawTextElementWithContainer; + expect(text.type).toBe("text"); + expect(text.containerId).toBe(rectangle.id); + expect(rectangle.boundElements).toStrictEqual([ + { id: text.id, type: "text" }, + ]); + expect(text.angle).toBe(rectangle.angle); + mouse.down(); + const editor = document.querySelector( + ".excalidraw-textEditorContainer > textarea", + ) as HTMLTextAreaElement; + + fireEvent.change(editor, { target: { value: "Hello World!" } }); + + await new Promise((r) => setTimeout(r, 0)); + editor.blur(); + expect(rectangle.boundElements).toStrictEqual([ + { id: text.id, type: "text" }, + ]); + }); + it("should compute the container height correctly and not throw error when height is updated while editing the text", async () => { const diamond = API.createElement({ type: "diamond", From 9368a9ce3ec3a49d92b0d8cf2a6910d94d7b6191 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 17:05:03 +0530 Subject: [PATCH 044/451] build(deps): bump webpack from 5.75.0 to 5.76.1 (#6357) Bumps [webpack](https://github.com/webpack/webpack) from 5.75.0 to 5.76.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.75.0...v5.76.1) --- updated-dependencies: - dependency-name: webpack dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 31624f92b..89d153909 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10601,9 +10601,9 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.64.4: - version "5.75.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152" - integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ== + version "5.76.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.76.1.tgz#7773de017e988bccb0f13c7d75ec245f377d295c" + integrity sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" From d12a9fdd40a10394a2f78f8cef825633ad0f0b87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 17:07:56 +0530 Subject: [PATCH 045/451] build(deps): bump ua-parser-js from 0.7.31 to 0.7.33 in /dev-docs (#6164) Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.31 to 0.7.33. - [Release notes](https://github.com/faisalman/ua-parser-js/releases) - [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md) - [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.31...0.7.33) --- updated-dependencies: - dependency-name: ua-parser-js dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dev-docs/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-docs/yarn.lock b/dev-docs/yarn.lock index ee3d50cbf..1b547bbbc 100644 --- a/dev-docs/yarn.lock +++ b/dev-docs/yarn.lock @@ -7159,9 +7159,9 @@ typescript@^4.7.4: integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== ua-parser-js@^0.7.30: - version "0.7.31" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" - integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== + version "0.7.33" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" + integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== unescape@^1.0.1: version "1.0.1" From c4445c181b9f1e87b346a38a6d3e39ed1e1e67b1 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Thu, 20 Apr 2023 17:34:06 +0530 Subject: [PATCH 046/451] =?UTF-8?q?docs:=20release=20@excalidraw/excalidra?= =?UTF-8?q?w@0.15.2=20=20=F0=9F=8E=89=20(#6495)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/excalidraw/CHANGELOG.md | 16 +++++++++++++++- src/packages/excalidraw/package.json | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index e69f05d0a..a2f7466b8 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -11,12 +11,26 @@ 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. --> -## Unreleased +## 0.15.2 (2023-04-20) ### Docs - Fix docs link in readme [#6486](https://github.com/excalidraw/excalidraw/pull/6486) +## Excalidraw Library + +**_This section lists the updates made to the excalidraw library and will not affect the integration._** + +### Fixes + +- Rotate the text element when binding to a rotated container [#6477](https://github.com/excalidraw/excalidraw/pull/6477) + +- Support breaking words containing hyphen - [#6014](https://github.com/excalidraw/excalidraw/pull/6014) + +- Incorrect background fill button active state [#6491](https://github.com/excalidraw/excalidraw/pull/6491) + +--- + ## 0.15.1 (2023-04-18) ### Docs diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index a59837454..57f6ce395 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -1,6 +1,6 @@ { "name": "@excalidraw/excalidraw", - "version": "0.15.1", + "version": "0.15.2", "main": "main.js", "types": "types/packages/excalidraw/index.d.ts", "files": [ From 2a4799d8c86964a3e3fd6f08defc3452c033d8c9 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Thu, 20 Apr 2023 17:40:08 +0530 Subject: [PATCH 047/451] chore: upgrade excalidraw version to 0.15.2 (#6496) chore: updragde excalidraw version to 0.15.2 --- dev-docs/package.json | 2 +- dev-docs/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev-docs/package.json b/dev-docs/package.json index 1e8745910..0aee8e01f 100644 --- a/dev-docs/package.json +++ b/dev-docs/package.json @@ -18,7 +18,7 @@ "@docusaurus/core": "2.2.0", "@docusaurus/preset-classic": "2.2.0", "@docusaurus/theme-live-codeblock": "2.2.0", - "@excalidraw/excalidraw": "0.15.0", + "@excalidraw/excalidraw": "0.15.2", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "docusaurus-plugin-sass": "0.2.3", diff --git a/dev-docs/yarn.lock b/dev-docs/yarn.lock index 1b547bbbc..6206a60e9 100644 --- a/dev-docs/yarn.lock +++ b/dev-docs/yarn.lock @@ -1631,10 +1631,10 @@ url-loader "^4.1.1" webpack "^5.73.0" -"@excalidraw/excalidraw@0.15.0": - version "0.15.0" - resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.15.0.tgz#47170de8d3ff006e9d09dfede2815682b0d4485b" - integrity sha512-PJmh1VcuRHG4l+Zgt9qhezxrJ16tYCZFZ8if5IEfmTL9A/7c5mXxY/qrPTqiGlVC7jYs+ciePXQ0YUDzfOfbzw== +"@excalidraw/excalidraw@0.15.2": + version "0.15.2" + resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.15.2.tgz#7dba4f6e10c52015a007efb75a9fc1afe598574c" + integrity sha512-rTI02kgWSTXiUdIkBxt9u/581F3eXcqQgJdIxmz54TFtG3ughoxO5fr4t7Fr2LZIturBPqfocQHGKZ0t2KLKgw== "@hapi/hoek@^9.0.0": version "9.3.0" From fee760d38c18c4d90c053b98d7cfa355707fc427 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Fri, 21 Apr 2023 22:53:49 +0200 Subject: [PATCH 048/451] feat: allow `avif`, `jfif`, `webp`, `bmp`, `ico` image types (#6500 * feat: allow `avif`, `jfif`, `webp`, `bmp`, `ico` image types * dedupe for SSOT * more SSOT --- src/components/App.tsx | 5 ++++- src/constants.ts | 32 ++++++++++++++++---------------- src/data/blob.ts | 8 +++----- src/data/filesystem.ts | 11 +---------- src/types.ts | 8 ++++---- 5 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 413a130d8..8000ea560 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -60,6 +60,7 @@ import { ENV, EVENT, GRID_SIZE, + IMAGE_MIME_TYPES, IMAGE_RENDER_TIMEOUT, isAndroid, isBrave, @@ -5743,7 +5744,9 @@ class App extends React.Component { const imageFile = await fileOpen({ description: "Image", - extensions: ["jpg", "png", "svg", "gif"], + extensions: Object.keys( + IMAGE_MIME_TYPES, + ) as (keyof typeof IMAGE_MIME_TYPES)[], }); const imageElement = this.createImageElement({ diff --git a/src/constants.ts b/src/constants.ts index 23fefa6e5..19b41b688 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -105,20 +105,30 @@ export const CANVAS_ONLY_ACTIONS = ["selectAll"]; export const GRID_SIZE = 20; // TODO make it configurable? -export const MIME_TYPES = { - excalidraw: "application/vnd.excalidraw+json", - excalidrawlib: "application/vnd.excalidrawlib+json", - json: "application/json", +export const IMAGE_MIME_TYPES = { svg: "image/svg+xml", - "excalidraw.svg": "image/svg+xml", png: "image/png", - "excalidraw.png": "image/png", jpg: "image/jpeg", gif: "image/gif", webp: "image/webp", bmp: "image/bmp", ico: "image/x-icon", + avif: "image/avif", + jfif: "image/jfif", +} as const; + +export const MIME_TYPES = { + json: "application/json", + // excalidraw data + excalidraw: "application/vnd.excalidraw+json", + excalidrawlib: "application/vnd.excalidrawlib+json", + // image-encoded excalidraw data + "excalidraw.svg": "image/svg+xml", + "excalidraw.png": "image/png", + // binary binary: "application/octet-stream", + // image + ...IMAGE_MIME_TYPES, } as const; export const EXPORT_DATA_TYPES = { @@ -189,16 +199,6 @@ export const DEFAULT_EXPORT_PADDING = 10; // px export const DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT = 1440; -export const ALLOWED_IMAGE_MIME_TYPES = [ - MIME_TYPES.png, - MIME_TYPES.jpg, - MIME_TYPES.svg, - MIME_TYPES.gif, - MIME_TYPES.webp, - MIME_TYPES.bmp, - MIME_TYPES.ico, -] as const; - export const MAX_ALLOWED_FILE_BYTES = 2 * 1024 * 1024; export const SVG_NS = "http://www.w3.org/2000/svg"; diff --git a/src/data/blob.ts b/src/data/blob.ts index 47cff293f..4565b5cb5 100644 --- a/src/data/blob.ts +++ b/src/data/blob.ts @@ -1,6 +1,6 @@ import { nanoid } from "nanoid"; import { cleanAppStateForExport } from "../appState"; -import { ALLOWED_IMAGE_MIME_TYPES, MIME_TYPES } from "../constants"; +import { IMAGE_MIME_TYPES, MIME_TYPES } from "../constants"; import { clearElementsForExport } from "../element"; import { ExcalidrawElement, FileId } from "../element/types"; import { CanvasError } from "../errors"; @@ -117,11 +117,9 @@ export const isImageFileHandle = (handle: FileSystemHandle | null) => { export const isSupportedImageFile = ( blob: Blob | null | undefined, -): blob is Blob & { type: typeof ALLOWED_IMAGE_MIME_TYPES[number] } => { +): blob is Blob & { type: ValueOf } => { const { type } = blob || {}; - return ( - !!type && (ALLOWED_IMAGE_MIME_TYPES as readonly string[]).includes(type) - ); + return !!type && (Object.values(IMAGE_MIME_TYPES) as string[]).includes(type); }; export const loadSceneOrLibraryFromBlob = async ( diff --git a/src/data/filesystem.ts b/src/data/filesystem.ts index ffe088faf..fa29604f4 100644 --- a/src/data/filesystem.ts +++ b/src/data/filesystem.ts @@ -8,16 +8,7 @@ import { EVENT, MIME_TYPES } from "../constants"; import { AbortError } from "../errors"; import { debounce } from "../utils"; -type FILE_EXTENSION = - | "gif" - | "jpg" - | "png" - | "excalidraw.png" - | "svg" - | "excalidraw.svg" - | "json" - | "excalidraw" - | "excalidrawlib"; +type FILE_EXTENSION = Exclude; const INPUT_CHANGE_INTERVAL_MS = 500; diff --git a/src/types.ts b/src/types.ts index 09848df1d..e5ad01b59 100644 --- a/src/types.ts +++ b/src/types.ts @@ -29,9 +29,9 @@ import { isOverScrollBars } from "./scene"; import { MaybeTransformHandleType } from "./element/transformHandles"; import Library from "./data/library"; import type { FileSystemHandle } from "./data/filesystem"; -import type { ALLOWED_IMAGE_MIME_TYPES, MIME_TYPES } from "./constants"; +import type { IMAGE_MIME_TYPES, MIME_TYPES } from "./constants"; import { ContextMenuItems } from "./components/ContextMenu"; -import { Merge, ForwardRef } from "./utility-types"; +import { Merge, ForwardRef, ValueOf } from "./utility-types"; import React from "react"; export type Point = Readonly; @@ -60,7 +60,7 @@ export type DataURL = string & { _brand: "DataURL" }; export type BinaryFileData = { mimeType: - | typeof ALLOWED_IMAGE_MIME_TYPES[number] + | ValueOf // future user or unknown file type | typeof MIME_TYPES.binary; id: FileId; @@ -419,7 +419,7 @@ export type AppClassProperties = { FileId, { image: HTMLImageElement | Promise; - mimeType: typeof ALLOWED_IMAGE_MIME_TYPES[number]; + mimeType: ValueOf; } >; files: BinaryFiles; From 9d5cfbbfb73c9abcf9ae534eb61548a9aa6fe225 Mon Sep 17 00:00:00 2001 From: zsviczian Date: Sat, 22 Apr 2023 14:17:13 +0200 Subject: [PATCH 049/451] fix: text jumps when editing on Android Chrome (#6503) * debug logging * debug * debugging * Update textWysiwyg.tsx * Update textWysiwyg.tsx * extended debug information * debug * debug * trace * further debug * don't drag while editing * removing all console.logs * revert all changes to textWysiwyt.tsx * updated comment --- src/components/App.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 8000ea560..546261436 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -4721,7 +4721,12 @@ class App extends React.Component { pointerDownState.drag.hasOccurred = true; // prevent dragging even if we're no longer holding cmd/ctrl otherwise // it would have weird results (stuff jumping all over the screen) - if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl) { + // Checking for editingElement to avoid jump while editing on mobile #6503 + if ( + selectedElements.length > 0 && + !pointerDownState.withCmdOrCtrl && + !this.state.editingElement + ) { const [dragX, dragY] = getGridPoint( pointerCoords.x - pointerDownState.drag.offset.x, pointerCoords.y - pointerDownState.drag.offset.y, From d35386755f951ae7612c2c793ad11d79503e3482 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Mon, 24 Apr 2023 10:26:21 +0200 Subject: [PATCH 050/451] feat: retain `seed` on shift-paste (#6509) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit thanks for the review 👍 --- src/actions/actionClipboard.tsx | 2 +- src/clipboard.ts | 38 ++++++++++++------ src/components/App.tsx | 5 +++ src/components/LibraryMenuItems.tsx | 2 +- src/element/newElement.ts | 17 +++++++- src/packages/utils.ts | 10 +---- src/tests/clipboard.test.tsx | 61 ++++++++++++++++++++--------- src/tests/flip.test.tsx | 21 ++++------ src/tests/test-utils.ts | 21 ++++++++++ 9 files changed, 120 insertions(+), 57 deletions(-) diff --git a/src/actions/actionClipboard.tsx b/src/actions/actionClipboard.tsx index 661f65f38..18fefafd2 100644 --- a/src/actions/actionClipboard.tsx +++ b/src/actions/actionClipboard.tsx @@ -18,7 +18,7 @@ export const actionCopy = register({ perform: (elements, appState, _, app) => { const selectedElements = getSelectedElements(elements, appState, true); - copyToClipboard(selectedElements, appState, app.files); + copyToClipboard(selectedElements, app.files); return { commitToHistory: false, diff --git a/src/clipboard.ts b/src/clipboard.ts index 5f7950c53..c0f5844dd 100644 --- a/src/clipboard.ts +++ b/src/clipboard.ts @@ -2,12 +2,12 @@ import { ExcalidrawElement, NonDeletedExcalidrawElement, } from "./element/types"; -import { AppState, BinaryFiles } from "./types"; +import { BinaryFiles } from "./types"; import { SVG_EXPORT_TAG } from "./scene/export"; import { tryParseSpreadsheet, Spreadsheet, VALID_SPREADSHEET } from "./charts"; import { EXPORT_DATA_TYPES, MIME_TYPES } from "./constants"; import { isInitializedImageElement } from "./element/typeChecks"; -import { isPromiseLike } from "./utils"; +import { isPromiseLike, isTestEnv } from "./utils"; type ElementsClipboard = { type: typeof EXPORT_DATA_TYPES.excalidrawClipboard; @@ -55,24 +55,40 @@ const clipboardContainsElements = ( export const copyToClipboard = async ( elements: readonly NonDeletedExcalidrawElement[], - appState: AppState, files: BinaryFiles | null, ) => { + let foundFile = false; + + const _files = elements.reduce((acc, element) => { + if (isInitializedImageElement(element)) { + foundFile = true; + if (files && files[element.fileId]) { + acc[element.fileId] = files[element.fileId]; + } + } + return acc; + }, {} as BinaryFiles); + + if (foundFile && !files) { + console.warn( + "copyToClipboard: attempting to file element(s) without providing associated `files` object.", + ); + } + // select binded text elements when copying const contents: ElementsClipboard = { type: EXPORT_DATA_TYPES.excalidrawClipboard, elements, - files: files - ? elements.reduce((acc, element) => { - if (isInitializedImageElement(element) && files[element.fileId]) { - acc[element.fileId] = files[element.fileId]; - } - return acc; - }, {} as BinaryFiles) - : undefined, + files: files ? _files : undefined, }; const json = JSON.stringify(contents); + + if (isTestEnv()) { + return json; + } + CLIPBOARD = json; + try { PREFER_APP_CLIPBOARD = false; await copyTextToSystemClipboard(json); diff --git a/src/components/App.tsx b/src/components/App.tsx index 546261436..d22a0507c 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1590,6 +1590,7 @@ class App extends React.Component { elements: data.elements, files: data.files || null, position: "cursor", + retainSeed: isPlainPaste, }); } else if (data.text) { this.addTextFromPaste(data.text, isPlainPaste); @@ -1603,6 +1604,7 @@ class App extends React.Component { elements: readonly ExcalidrawElement[]; files: BinaryFiles | null; position: { clientX: number; clientY: number } | "cursor" | "center"; + retainSeed?: boolean; }) => { const elements = restoreElements(opts.elements, null); const [minX, minY, maxX, maxY] = getCommonBounds(elements); @@ -1640,6 +1642,9 @@ class App extends React.Component { y: element.y + gridY - minY, }); }), + { + randomizeSeed: !opts.retainSeed, + }, ); const nextElements = [ diff --git a/src/components/LibraryMenuItems.tsx b/src/components/LibraryMenuItems.tsx index 7ae6517a8..19bb33308 100644 --- a/src/components/LibraryMenuItems.tsx +++ b/src/components/LibraryMenuItems.tsx @@ -102,7 +102,7 @@ const LibraryMenuItems = ({ ...item, // duplicate each library item before inserting on canvas to confine // ids and bindings to each library item. See #6465 - elements: duplicateElements(item.elements), + elements: duplicateElements(item.elements, { randomizeSeed: true }), }; }); }; diff --git a/src/element/newElement.ts b/src/element/newElement.ts index 36c8cc0e0..c1b0f17bf 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -20,7 +20,7 @@ import { isTestEnv, } from "../utils"; import { randomInteger, randomId } from "../random"; -import { mutateElement, newElementWith } from "./mutateElement"; +import { bumpVersion, mutateElement, newElementWith } from "./mutateElement"; import { getNewGroupIdsForDuplication } from "../groups"; import { AppState } from "../types"; import { getElementAbsoluteCoords } from "."; @@ -539,8 +539,16 @@ export const duplicateElement = ( * it's advised to supply the whole elements array, or sets of elements that * are encapsulated (such as library items), if the purpose is to retain * bindings to the cloned elements intact. + * + * NOTE by default does not randomize or regenerate anything except the id. */ -export const duplicateElements = (elements: readonly ExcalidrawElement[]) => { +export const duplicateElements = ( + elements: readonly ExcalidrawElement[], + opts?: { + /** NOTE also updates version flags and `updated` */ + randomizeSeed: boolean; + }, +) => { const clonedElements: ExcalidrawElement[] = []; const origElementsMap = arrayToMap(elements); @@ -574,6 +582,11 @@ export const duplicateElements = (elements: readonly ExcalidrawElement[]) => { clonedElement.id = maybeGetNewId(element.id)!; + if (opts?.randomizeSeed) { + clonedElement.seed = randomInteger(); + bumpVersion(clonedElement); + } + if (clonedElement.groupIds) { clonedElement.groupIds = clonedElement.groupIds.map((groupId) => { if (!groupNewIdsMap.has(groupId)) { diff --git a/src/packages/utils.ts b/src/packages/utils.ts index 560fa13ca..d9365895e 100644 --- a/src/packages/utils.ts +++ b/src/packages/utils.ts @@ -220,15 +220,7 @@ export const exportToClipboard = async ( } else if (opts.type === "png") { await copyBlobToClipboardAsPng(exportToBlob(opts)); } else if (opts.type === "json") { - const appState = { - offsetTop: 0, - offsetLeft: 0, - width: 0, - height: 0, - ...getDefaultAppState(), - ...opts.appState, - }; - await copyToClipboard(opts.elements, appState, opts.files); + await copyToClipboard(opts.elements, opts.files); } else { throw new Error("Invalid export type"); } diff --git a/src/tests/clipboard.test.tsx b/src/tests/clipboard.test.tsx index 1fdc0f452..bbaa4d179 100644 --- a/src/tests/clipboard.test.tsx +++ b/src/tests/clipboard.test.tsx @@ -1,5 +1,10 @@ import ReactDOM from "react-dom"; -import { render, waitFor, GlobalTestState } from "./test-utils"; +import { + render, + waitFor, + GlobalTestState, + createPasteEvent, +} from "./test-utils"; import { Pointer, Keyboard } from "./helpers/ui"; import ExcalidrawApp from "../excalidraw-app"; import { KEYS } from "../keys"; @@ -9,6 +14,8 @@ import { } from "../element/textElement"; import { getElementBounds } from "../element"; import { NormalizedZoomValue } from "../types"; +import { API } from "./helpers/api"; +import { copyToClipboard } from "../clipboard"; const { h } = window; @@ -35,38 +42,28 @@ const setClipboardText = (text: string) => { }); }; -const sendPasteEvent = () => { - const clipboardEvent = new Event("paste", { - bubbles: true, - cancelable: true, - composed: true, - }); - - // set `clipboardData` properties. - // @ts-ignore - clipboardEvent.clipboardData = { - getData: () => window.navigator.clipboard.readText(), - files: [], - }; - +const sendPasteEvent = (text?: string) => { + const clipboardEvent = createPasteEvent( + text || (() => window.navigator.clipboard.readText()), + ); document.dispatchEvent(clipboardEvent); }; -const pasteWithCtrlCmdShiftV = () => { +const pasteWithCtrlCmdShiftV = (text?: string) => { Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => { //triggering keydown with an empty clipboard Keyboard.keyPress(KEYS.V); //triggering paste event with faked clipboard - sendPasteEvent(); + sendPasteEvent(text); }); }; -const pasteWithCtrlCmdV = () => { +const pasteWithCtrlCmdV = (text?: string) => { Keyboard.withModifierKeys({ ctrl: true }, () => { //triggering keydown with an empty clipboard Keyboard.keyPress(KEYS.V); //triggering paste event with faked clipboard - sendPasteEvent(); + sendPasteEvent(text); }); }; @@ -89,6 +86,32 @@ beforeEach(async () => { }); }); +describe("general paste behavior", () => { + it("should randomize seed on paste", async () => { + const rectangle = API.createElement({ type: "rectangle" }); + const clipboardJSON = (await copyToClipboard([rectangle], null))!; + + pasteWithCtrlCmdV(clipboardJSON); + + await waitFor(() => { + expect(h.elements.length).toBe(1); + expect(h.elements[0].seed).not.toBe(rectangle.seed); + }); + }); + + it("should retain seed on shift-paste", async () => { + const rectangle = API.createElement({ type: "rectangle" }); + const clipboardJSON = (await copyToClipboard([rectangle], null))!; + + // assert we don't randomize seed on shift-paste + pasteWithCtrlCmdShiftV(clipboardJSON); + await waitFor(() => { + expect(h.elements.length).toBe(1); + expect(h.elements[0].seed).toBe(rectangle.seed); + }); + }); +}); + describe("paste text as single lines", () => { it("should create an element for each line when copying with Ctrl/Cmd+V", async () => { const text = "sajgfakfn\naaksfnknas\nakefnkasf"; diff --git a/src/tests/flip.test.tsx b/src/tests/flip.test.tsx index 45a5e1477..c1469bc83 100644 --- a/src/tests/flip.test.tsx +++ b/src/tests/flip.test.tsx @@ -1,5 +1,10 @@ import ReactDOM from "react-dom"; -import { GlobalTestState, render, waitFor } from "./test-utils"; +import { + createPasteEvent, + GlobalTestState, + render, + waitFor, +} from "./test-utils"; import { UI, Pointer } from "./helpers/ui"; import { API } from "./helpers/api"; import { actionFlipHorizontal, actionFlipVertical } from "../actions"; @@ -680,19 +685,7 @@ describe("freedraw", () => { describe("image", () => { const createImage = async () => { const sendPasteEvent = (file?: File) => { - const clipboardEvent = new Event("paste", { - bubbles: true, - cancelable: true, - composed: true, - }); - - // set `clipboardData` properties. - // @ts-ignore - clipboardEvent.clipboardData = { - getData: () => window.navigator.clipboard.readText(), - files: [file], - }; - + const clipboardEvent = createPasteEvent("", file ? [file] : []); document.dispatchEvent(clipboardEvent); }; diff --git a/src/tests/test-utils.ts b/src/tests/test-utils.ts index c33e80c7d..9560f681f 100644 --- a/src/tests/test-utils.ts +++ b/src/tests/test-utils.ts @@ -190,3 +190,24 @@ export const toggleMenu = (container: HTMLElement) => { // open menu fireEvent.click(container.querySelector(".dropdown-menu-button")!); }; + +export const createPasteEvent = ( + text: + | string + | /* getData function */ ((type: string) => string | Promise), + files?: File[], +) => { + return Object.assign( + new Event("paste", { + bubbles: true, + cancelable: true, + composed: true, + }), + { + clipboardData: { + getData: typeof text === "string" ? () => text : text, + files: files || [], + }, + }, + ); +}; From 1815cf3213b1d19cb6aa1a54dabd969196a65a28 Mon Sep 17 00:00:00 2001 From: Nainterceptor Date: Tue, 25 Apr 2023 13:21:25 +0200 Subject: [PATCH 051/451] build: Add version tags to Docker build (#6508) ci: Add version tags --- .github/workflows/publish-docker.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index a4a8a4c5f..3602bb660 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -12,14 +12,24 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: | + excalidraw/excalidraw + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} - name: Login to DockerHub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . push: true - tags: excalidraw/excalidraw:latest + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From 1e9943323ad5f34bb4efc48c5b5a9b01387dbc36 Mon Sep 17 00:00:00 2001 From: suwalkanishka Date: Tue, 25 Apr 2023 17:35:19 +0545 Subject: [PATCH 052/451] style: fix font family inconsistencies (#6501) style: font fix for four components The browser default font was showing up in various locations. Fixed them to show the desired ui font. --- src/components/ColorPicker.scss | 1 + src/components/ContextMenu.scss | 1 + src/components/Tooltip.scss | 3 +++ src/css/styles.scss | 2 ++ 4 files changed, 7 insertions(+) diff --git a/src/components/ColorPicker.scss b/src/components/ColorPicker.scss index 52ea20a19..b816b2553 100644 --- a/src/components/ColorPicker.scss +++ b/src/components/ColorPicker.scss @@ -183,6 +183,7 @@ width: 100%; margin: 0; font-size: 0.875rem; + font-family: inherit; background-color: transparent; color: var(--text-primary-color); border: 0; diff --git a/src/components/ContextMenu.scss b/src/components/ContextMenu.scss index 579763119..81ced3880 100644 --- a/src/components/ContextMenu.scss +++ b/src/components/ContextMenu.scss @@ -30,6 +30,7 @@ background-color: transparent; border: none; white-space: nowrap; + font-family: inherit; display: grid; grid-template-columns: 1fr 0.2fr; diff --git a/src/components/Tooltip.scss b/src/components/Tooltip.scss index bb2b2f72e..490e25578 100644 --- a/src/components/Tooltip.scss +++ b/src/components/Tooltip.scss @@ -2,6 +2,9 @@ // container in body where the actual tooltip is appended to .excalidraw-tooltip { + --ui-font: Assistant, system-ui, BlinkMacSystemFont, -apple-system, Segoe UI, + Roboto, Helvetica, Arial, sans-serif; + font-family: var(--ui-font); position: fixed; z-index: 1000; diff --git a/src/css/styles.scss b/src/css/styles.scss index 8dafbfbdf..29e52011e 100644 --- a/src/css/styles.scss +++ b/src/css/styles.scss @@ -354,6 +354,7 @@ border-radius: var(--space-factor); border: 1px solid var(--button-gray-2); font-size: 0.8rem; + font-family: inherit; outline: none; appearance: none; background-image: var(--dropdown-icon); @@ -413,6 +414,7 @@ bottom: 30px; transform: translateX(-50%); pointer-events: all; + font-family: inherit; &:hover { background-color: var(--button-hover-bg); From dae81c0a2cb8c21381830635d5bb992eb30b6f36 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 25 Apr 2023 17:57:53 +0530 Subject: [PATCH 053/451] fix: cleanup redrawTextBoundingBox (#6518) * chore: cleanup redrawTextBoundingBox * fix --- src/element/textElement.ts | 44 +++++++++++++++----------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/src/element/textElement.ts b/src/element/textElement.ts index f01ba3e1b..339f68b96 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -83,35 +83,25 @@ export const redrawTextBoundingBox = ( boundTextUpdates.baseline = metrics.baseline; if (container) { - if (isArrowElement(container)) { - const centerX = textElement.x + textElement.width / 2; - const centerY = textElement.y + textElement.height / 2; - const diffWidth = metrics.width - textElement.width; - const diffHeight = metrics.height - textElement.height; - boundTextUpdates.x = centerY - (textElement.height + diffHeight) / 2; - boundTextUpdates.y = centerX - (textElement.width + diffWidth) / 2; - } else { - const containerDims = getContainerDims(container); - let maxContainerHeight = getMaxContainerHeight(container); + const containerDims = getContainerDims(container); + const maxContainerHeight = getMaxContainerHeight(container); - let nextHeight = containerDims.height; - if (metrics.height > maxContainerHeight) { - nextHeight = computeContainerDimensionForBoundText( - metrics.height, - container.type, - ); - mutateElement(container, { height: nextHeight }); - maxContainerHeight = getMaxContainerHeight(container); - updateOriginalContainerCache(container.id, nextHeight); - } - const updatedTextElement = { - ...textElement, - ...boundTextUpdates, - } as ExcalidrawTextElementWithContainer; - const { x, y } = computeBoundTextPosition(container, updatedTextElement); - boundTextUpdates.x = x; - boundTextUpdates.y = y; + let nextHeight = containerDims.height; + if (metrics.height > maxContainerHeight) { + nextHeight = computeContainerDimensionForBoundText( + metrics.height, + container.type, + ); + mutateElement(container, { height: nextHeight }); + updateOriginalContainerCache(container.id, nextHeight); } + const updatedTextElement = { + ...textElement, + ...boundTextUpdates, + } as ExcalidrawTextElementWithContainer; + const { x, y } = computeBoundTextPosition(container, updatedTextElement); + boundTextUpdates.x = x; + boundTextUpdates.y = y; } mutateElement(textElement, boundTextUpdates); From da8dd389a9dd7e6528fbd6bf85b12e8ec052f325 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 25 Apr 2023 18:06:23 +0530 Subject: [PATCH 054/451] fix: cleanup getMaxContainerHeight and getMaxContainerWidth (#6519) * fix: cleanup getMaxContainerHeight and getMaxContainerWidth * rename getMaxContainerWidth -> getBoundTextMaxMaxWidth and getMaxContainerHeight -> getBoundTextMaxHeight * add specs --- src/element/newElement.ts | 4 +- src/element/resizeElements.ts | 14 +++--- src/element/textElement.test.ts | 59 +++++++++++++++++++++----- src/element/textElement.ts | 41 +++++++++--------- src/element/textWysiwyg.tsx | 15 ++++--- src/renderer/renderElement.ts | 11 +++-- src/tests/linearElementEditor.test.tsx | 8 ++-- 7 files changed, 96 insertions(+), 56 deletions(-) diff --git a/src/element/newElement.ts b/src/element/newElement.ts index c1b0f17bf..4922a5b4e 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -33,7 +33,7 @@ import { measureText, normalizeText, wrapText, - getMaxContainerWidth, + getBoundTextMaxWidth, getDefaultLineHeight, } from "./textElement"; import { @@ -310,7 +310,7 @@ export const refreshTextDimensions = ( text = wrapText( text, getFontString(textElement), - getMaxContainerWidth(container), + getBoundTextMaxWidth(container), ); } const dimensions = getAdjustedDimensions(textElement, text); diff --git a/src/element/resizeElements.ts b/src/element/resizeElements.ts index 69b8afae7..67a6346be 100644 --- a/src/element/resizeElements.ts +++ b/src/element/resizeElements.ts @@ -44,10 +44,10 @@ import { getBoundTextElementId, getContainerElement, handleBindTextResize, - getMaxContainerWidth, + getBoundTextMaxWidth, getApproxMinLineHeight, measureText, - getMaxContainerHeight, + getBoundTextMaxHeight, } from "./textElement"; export const normalizeAngle = (angle: number): number => { @@ -204,7 +204,7 @@ const measureFontSizeFromWidth = ( if (hasContainer) { const container = getContainerElement(element); if (container) { - width = getMaxContainerWidth(container); + width = getBoundTextMaxWidth(container); } } const nextFontSize = element.fontSize * (nextWidth / width); @@ -435,8 +435,8 @@ export const resizeSingleElement = ( const nextFont = measureFontSizeFromWidth( boundTextElement, - getMaxContainerWidth(updatedElement), - getMaxContainerHeight(updatedElement), + getBoundTextMaxWidth(updatedElement), + getBoundTextMaxHeight(updatedElement, boundTextElement), ); if (nextFont === null) { return; @@ -718,10 +718,10 @@ const resizeMultipleElements = ( const metrics = measureFontSizeFromWidth( boundTextElement ?? (element.orig as ExcalidrawTextElement), boundTextElement - ? getMaxContainerWidth(updatedElement) + ? getBoundTextMaxWidth(updatedElement) : updatedElement.width, boundTextElement - ? getMaxContainerHeight(updatedElement) + ? getBoundTextMaxHeight(updatedElement, boundTextElement) : updatedElement.height, ); diff --git a/src/element/textElement.test.ts b/src/element/textElement.test.ts index f83eafd1b..b6221336d 100644 --- a/src/element/textElement.test.ts +++ b/src/element/textElement.test.ts @@ -3,15 +3,15 @@ import { API } from "../tests/helpers/api"; import { computeContainerDimensionForBoundText, getContainerCoords, - getMaxContainerWidth, - getMaxContainerHeight, + getBoundTextMaxWidth, + getBoundTextMaxHeight, wrapText, detectLineHeight, getLineHeightInPx, getDefaultLineHeight, parseTokens, } from "./textElement"; -import { FontString } from "./types"; +import { ExcalidrawTextElementWithContainer, FontString } from "./types"; describe("Test wrapText", () => { const font = "20px Cascadia, width: Segoe UI Emoji" as FontString; @@ -311,7 +311,7 @@ describe("Test measureText", () => { }); }); - describe("Test getMaxContainerWidth", () => { + describe("Test getBoundTextMaxWidth", () => { const params = { width: 178, height: 194, @@ -319,39 +319,76 @@ describe("Test measureText", () => { it("should return max width when container is rectangle", () => { const container = API.createElement({ type: "rectangle", ...params }); - expect(getMaxContainerWidth(container)).toBe(168); + expect(getBoundTextMaxWidth(container)).toBe(168); }); it("should return max width when container is ellipse", () => { const container = API.createElement({ type: "ellipse", ...params }); - expect(getMaxContainerWidth(container)).toBe(116); + expect(getBoundTextMaxWidth(container)).toBe(116); }); it("should return max width when container is diamond", () => { const container = API.createElement({ type: "diamond", ...params }); - expect(getMaxContainerWidth(container)).toBe(79); + expect(getBoundTextMaxWidth(container)).toBe(79); }); }); - describe("Test getMaxContainerHeight", () => { + describe("Test getBoundTextMaxHeight", () => { const params = { width: 178, height: 194, + id: '"container-id', }; + const boundTextElement = API.createElement({ + type: "text", + id: "text-id", + x: 560.51171875, + y: 202.033203125, + width: 154, + height: 175, + fontSize: 20, + fontFamily: 1, + text: "Excalidraw is a\nvirtual \nopensource \nwhiteboard for \nsketching \nhand-drawn like\ndiagrams", + textAlign: "center", + verticalAlign: "middle", + containerId: params.id, + }) as ExcalidrawTextElementWithContainer; + it("should return max height when container is rectangle", () => { const container = API.createElement({ type: "rectangle", ...params }); - expect(getMaxContainerHeight(container)).toBe(184); + expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(184); }); it("should return max height when container is ellipse", () => { const container = API.createElement({ type: "ellipse", ...params }); - expect(getMaxContainerHeight(container)).toBe(127); + expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(127); }); it("should return max height when container is diamond", () => { const container = API.createElement({ type: "diamond", ...params }); - expect(getMaxContainerHeight(container)).toBe(87); + expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(87); + }); + + it("should return max height when container is arrow", () => { + const container = API.createElement({ + type: "arrow", + ...params, + }); + expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(194); + }); + + it("should return max height when container is arrow and height is less than threshold", () => { + const container = API.createElement({ + type: "arrow", + ...params, + height: 70, + boundElements: [{ type: "text", id: "text-id" }], + }); + + expect(getBoundTextMaxHeight(container, boundTextElement)).toBe( + boundTextElement.height, + ); }); }); }); diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 339f68b96..a6d0c3271 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -65,7 +65,7 @@ export const redrawTextBoundingBox = ( boundTextUpdates.text = textElement.text; if (container) { - maxWidth = getMaxContainerWidth(container); + maxWidth = getBoundTextMaxWidth(container); boundTextUpdates.text = wrapText( textElement.originalText, getFontString(textElement), @@ -84,7 +84,10 @@ export const redrawTextBoundingBox = ( if (container) { const containerDims = getContainerDims(container); - const maxContainerHeight = getMaxContainerHeight(container); + const maxContainerHeight = getBoundTextMaxHeight( + container, + textElement as ExcalidrawTextElementWithContainer, + ); let nextHeight = containerDims.height; if (metrics.height > maxContainerHeight) { @@ -173,8 +176,11 @@ export const handleBindTextResize = ( let nextHeight = textElement.height; let nextWidth = textElement.width; const containerDims = getContainerDims(container); - const maxWidth = getMaxContainerWidth(container); - const maxHeight = getMaxContainerHeight(container); + const maxWidth = getBoundTextMaxWidth(container); + const maxHeight = getBoundTextMaxHeight( + container, + textElement as ExcalidrawTextElementWithContainer, + ); let containerHeight = containerDims.height; let nextBaseLine = textElement.baseline; if (transformHandleType !== "n" && transformHandleType !== "s") { @@ -246,8 +252,8 @@ export const computeBoundTextPosition = ( ); } const containerCoords = getContainerCoords(container); - const maxContainerHeight = getMaxContainerHeight(container); - const maxContainerWidth = getMaxContainerWidth(container); + const maxContainerHeight = getBoundTextMaxHeight(container, boundTextElement); + const maxContainerWidth = getBoundTextMaxWidth(container); let x; let y; @@ -880,18 +886,10 @@ export const computeContainerDimensionForBoundText = ( return dimension + padding; }; -export const getMaxContainerWidth = (container: ExcalidrawElement) => { +export const getBoundTextMaxWidth = (container: ExcalidrawElement) => { const width = getContainerDims(container).width; if (isArrowElement(container)) { - const containerWidth = width - BOUND_TEXT_PADDING * 8 * 2; - if (containerWidth <= 0) { - const boundText = getBoundTextElement(container); - if (boundText) { - return boundText.width; - } - return BOUND_TEXT_PADDING * 8 * 2; - } - return containerWidth; + return width - BOUND_TEXT_PADDING * 8 * 2; } if (container.type === "ellipse") { @@ -908,16 +906,15 @@ export const getMaxContainerWidth = (container: ExcalidrawElement) => { return width - BOUND_TEXT_PADDING * 2; }; -export const getMaxContainerHeight = (container: ExcalidrawElement) => { +export const getBoundTextMaxHeight = ( + container: ExcalidrawElement, + boundTextElement: ExcalidrawTextElementWithContainer, +) => { const height = getContainerDims(container).height; if (isArrowElement(container)) { const containerHeight = height - BOUND_TEXT_PADDING * 8 * 2; if (containerHeight <= 0) { - const boundText = getBoundTextElement(container); - if (boundText) { - return boundText.height; - } - return BOUND_TEXT_PADDING * 8 * 2; + return boundTextElement.height; } return height; } diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index ef4f7c926..63bc9e4a4 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -32,8 +32,8 @@ import { normalizeText, redrawTextBoundingBox, wrapText, - getMaxContainerHeight, - getMaxContainerWidth, + getBoundTextMaxHeight, + getBoundTextMaxWidth, computeContainerDimensionForBoundText, detectLineHeight, } from "./textElement"; @@ -205,8 +205,11 @@ export const textWysiwyg = ({ } } - maxWidth = getMaxContainerWidth(container); - maxHeight = getMaxContainerHeight(container); + maxWidth = getBoundTextMaxWidth(container); + maxHeight = getBoundTextMaxHeight( + container, + updatedTextElement as ExcalidrawTextElementWithContainer, + ); // autogrow container height if text exceeds if (!isArrowElement(container) && textElementHeight > maxHeight) { @@ -377,7 +380,7 @@ export const textWysiwyg = ({ const wrappedText = wrapText( `${editable.value}${data}`, font, - getMaxContainerWidth(container), + getBoundTextMaxWidth(container), ); const width = getTextWidth(wrappedText, font); editable.style.width = `${width}px`; @@ -394,7 +397,7 @@ export const textWysiwyg = ({ const wrappedText = wrapText( normalizeText(editable.value), font, - getMaxContainerWidth(container!), + getBoundTextMaxWidth(container!), ); const { width, height } = measureText( wrappedText, diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index f85c83a6b..77ea14587 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -44,8 +44,8 @@ import { getContainerCoords, getContainerElement, getLineHeightInPx, - getMaxContainerHeight, - getMaxContainerWidth, + getBoundTextMaxHeight, + getBoundTextMaxWidth, } from "../element/textElement"; import { LinearElementEditor } from "../element/linearElementEditor"; @@ -868,14 +868,17 @@ const drawElementFromCanvas = ( "true" && hasBoundTextElement(element) ) { + const textElement = getBoundTextElement( + element, + ) as ExcalidrawTextElementWithContainer; const coords = getContainerCoords(element); context.strokeStyle = "#c92a2a"; context.lineWidth = 3; context.strokeRect( (coords.x + renderConfig.scrollX) * window.devicePixelRatio, (coords.y + renderConfig.scrollY) * window.devicePixelRatio, - getMaxContainerWidth(element) * window.devicePixelRatio, - getMaxContainerHeight(element) * window.devicePixelRatio, + getBoundTextMaxWidth(element) * window.devicePixelRatio, + getBoundTextMaxHeight(element, textElement) * window.devicePixelRatio, ); } } diff --git a/src/tests/linearElementEditor.test.tsx b/src/tests/linearElementEditor.test.tsx index 15fd105ec..c71283a4c 100644 --- a/src/tests/linearElementEditor.test.tsx +++ b/src/tests/linearElementEditor.test.tsx @@ -20,7 +20,7 @@ import { resize, rotate } from "./utils"; import { getBoundTextElementPosition, wrapText, - getMaxContainerWidth, + getBoundTextMaxWidth, } from "../element/textElement"; import * as textElementUtils from "../element/textElement"; import { ROUNDNESS, VERTICAL_ALIGN } from "../constants"; @@ -729,7 +729,7 @@ describe("Test Linear Elements", () => { type: "text", x: 0, y: 0, - text: wrapText(text, font, getMaxContainerWidth(container)), + text: wrapText(text, font, getBoundTextMaxWidth(container)), containerId: container.id, width: 30, height: 20, @@ -1149,7 +1149,7 @@ describe("Test Linear Elements", () => { expect(rect.x).toBe(400); expect(rect.y).toBe(0); expect( - wrapText(textElement.originalText, font, getMaxContainerWidth(arrow)), + wrapText(textElement.originalText, font, getBoundTextMaxWidth(arrow)), ).toMatchInlineSnapshot(` "Online whiteboard collaboration made easy" @@ -1172,7 +1172,7 @@ describe("Test Linear Elements", () => { false, ); expect( - wrapText(textElement.originalText, font, getMaxContainerWidth(arrow)), + wrapText(textElement.originalText, font, getBoundTextMaxWidth(arrow)), ).toMatchInlineSnapshot(` "Online whiteboard collaboration made From 45a57d70de75fbb47f7c3c45cae675341c9bcab5 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Wed, 26 Apr 2023 21:35:06 +0530 Subject: [PATCH 055/451] fix: don't refresh dimensions for text containers on font load (#6523) --- src/data/blob.ts | 2 +- src/excalidraw-app/data/index.ts | 2 +- src/scene/Fonts.ts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/data/blob.ts b/src/data/blob.ts index 4565b5cb5..c0aa66ee7 100644 --- a/src/data/blob.ts +++ b/src/data/blob.ts @@ -155,7 +155,7 @@ export const loadSceneOrLibraryFromBlob = async ( }, localAppState, localElements, - { repairBindings: true, refreshDimensions: true }, + { repairBindings: true, refreshDimensions: false }, ), }; } else if (isValidLibrary(data)) { diff --git a/src/excalidraw-app/data/index.ts b/src/excalidraw-app/data/index.ts index 7f13bc615..2e50abf1f 100644 --- a/src/excalidraw-app/data/index.ts +++ b/src/excalidraw-app/data/index.ts @@ -263,7 +263,7 @@ export const loadScene = async ( await importFromBackend(id, privateKey), localDataState?.appState, localDataState?.elements, - { repairBindings: true, refreshDimensions: true }, + { repairBindings: true, refreshDimensions: false }, ); } else { data = restore(localDataState || null, null, null, { diff --git a/src/scene/Fonts.ts b/src/scene/Fonts.ts index cc206c776..e245eb16e 100644 --- a/src/scene/Fonts.ts +++ b/src/scene/Fonts.ts @@ -1,5 +1,6 @@ import { isTextElement, refreshTextDimensions } from "../element"; import { newElementWith } from "../element/mutateElement"; +import { isBoundToContainer } from "../element/typeChecks"; import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types"; import { invalidateShapeForElement } from "../renderer/renderElement"; import { getFontString } from "../utils"; @@ -52,7 +53,7 @@ export class Fonts { let didUpdate = false; this.scene.mapElements((element) => { - if (isTextElement(element)) { + if (isTextElement(element) && !isBoundToContainer(element)) { invalidateShapeForElement(element); didUpdate = true; return newElementWith(element, { From 6b0218b01251dfd2143cd974279b70e10a2180a6 Mon Sep 17 00:00:00 2001 From: Milos Vetesnik Date: Thu, 27 Apr 2023 19:11:42 +0200 Subject: [PATCH 056/451] feat: testing simple analytics and fathom analytics for better privacy of the users (#6529) Co-authored-by: dwelle --- public/index.html | 45 ++++++++++++++++++++------------------------- src/analytics.ts | 17 ++++++++++++++--- src/global.d.ts | 4 ++-- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/public/index.html b/public/index.html index a8633fc4d..f65e481f3 100644 --- a/public/index.html +++ b/public/index.html @@ -150,6 +150,14 @@ <% if (process.env.REACT_APP_DISABLE_TRACKING !== 'true') { %> + + + + <% if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID) { %> - <% } %> - - <% } %> @@ -244,5 +227,17 @@

Excalidraw

+ + + diff --git a/src/analytics.ts b/src/analytics.ts index 1e9a429b6..e952bc680 100644 --- a/src/analytics.ts +++ b/src/analytics.ts @@ -20,9 +20,20 @@ export const trackEvent = ( }); } - // MATOMO event tracking _paq must be same as the one in index.html - if (window._paq) { - window._paq.push(["trackEvent", category, action, label, value]); + if (window.sa_event) { + window.sa_event(action, { + category, + label, + value, + }); + } + + if (window.fathom) { + window.fathom.trackEvent(action, { + category, + label, + value, + }); } } catch (error) { console.error("error during analytics", error); diff --git a/src/global.d.ts b/src/global.d.ts index 73c8fc813..3a666e11a 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -18,8 +18,8 @@ interface Window { EXCALIDRAW_EXPORT_SOURCE: string; EXCALIDRAW_THROTTLE_RENDER: boolean | undefined; gtag: Function; - _paq: any[]; - _mtm: any[]; + sa_event: Function; + fathom: { trackEvent: Function }; } interface CanvasRenderingContext2D { From 2a39d0b9a72b65679d213683cf4786d847a29dc6 Mon Sep 17 00:00:00 2001 From: Excalidraw Bot <77840495+excalibot@users.noreply.github.com> Date: Thu, 27 Apr 2023 19:27:36 +0200 Subject: [PATCH 057/451] chore: Update translations from Crowdin (#6471) --- src/locales/ar-SA.json | 1 + src/locales/bg-BG.json | 1 + src/locales/bn-BD.json | 1 + src/locales/ca-ES.json | 1 + src/locales/cs-CZ.json | 1 + src/locales/da-DK.json | 1 + src/locales/de-DE.json | 1 + src/locales/el-GR.json | 1 + src/locales/es-ES.json | 9 ++--- src/locales/eu-ES.json | 1 + src/locales/fa-IR.json | 1 + src/locales/fi-FI.json | 1 + src/locales/fr-FR.json | 5 +-- src/locales/gl-ES.json | 1 + src/locales/he-IL.json | 1 + src/locales/hi-IN.json | 1 + src/locales/hu-HU.json | 1 + src/locales/id-ID.json | 1 + src/locales/it-IT.json | 3 +- src/locales/ja-JP.json | 1 + src/locales/kab-KAB.json | 1 + src/locales/kk-KZ.json | 1 + src/locales/ko-KR.json | 11 +++--- src/locales/ku-TR.json | 69 ++++++++++++++++++------------------ src/locales/lt-LT.json | 1 + src/locales/lv-LV.json | 55 ++++++++++++++-------------- src/locales/mr-IN.json | 1 + src/locales/my-MM.json | 1 + src/locales/nb-NO.json | 1 + src/locales/nl-NL.json | 1 + src/locales/nn-NO.json | 1 + src/locales/oc-FR.json | 1 + src/locales/pa-IN.json | 1 + src/locales/percentages.json | 36 +++++++++---------- src/locales/pl-PL.json | 1 + src/locales/pt-BR.json | 1 + src/locales/pt-PT.json | 5 +-- src/locales/ro-RO.json | 1 + src/locales/ru-RU.json | 33 ++++++++--------- src/locales/si-LK.json | 1 + src/locales/sk-SK.json | 5 +-- src/locales/sl-SI.json | 1 + src/locales/sv-SE.json | 5 +-- src/locales/ta-IN.json | 1 + src/locales/th-TH.json | 1 + src/locales/tr-TR.json | 1 + src/locales/uk-UA.json | 1 + src/locales/vi-VN.json | 1 + src/locales/zh-CN.json | 5 +-- src/locales/zh-HK.json | 1 + src/locales/zh-TW.json | 1 + 51 files changed, 165 insertions(+), 115 deletions(-) diff --git a/src/locales/ar-SA.json b/src/locales/ar-SA.json index 25a32f222..77387b11d 100644 --- a/src/locales/ar-SA.json +++ b/src/locales/ar-SA.json @@ -54,6 +54,7 @@ "veryLarge": "كبير جدا", "solid": "كامل", "hachure": "خطوط", + "zigzag": "", "crossHatch": "خطوط متقطعة", "thin": "نحيف", "bold": "داكن", diff --git a/src/locales/bg-BG.json b/src/locales/bg-BG.json index 501ce7399..d5421ccef 100644 --- a/src/locales/bg-BG.json +++ b/src/locales/bg-BG.json @@ -54,6 +54,7 @@ "veryLarge": "Много голям", "solid": "Солиден", "hachure": "Хералдика", + "zigzag": "", "crossHatch": "Двойно-пресечено", "thin": "Тънък", "bold": "Ясно очертан", diff --git a/src/locales/bn-BD.json b/src/locales/bn-BD.json index a5d9dec0f..ce17d6670 100644 --- a/src/locales/bn-BD.json +++ b/src/locales/bn-BD.json @@ -54,6 +54,7 @@ "veryLarge": "অনেক বড়", "solid": "দৃঢ়", "hachure": "ভ্রুলেখা", + "zigzag": "", "crossHatch": "ক্রস হ্যাচ", "thin": "পাতলা", "bold": "পুরু", diff --git a/src/locales/ca-ES.json b/src/locales/ca-ES.json index ae45e764d..425070e49 100644 --- a/src/locales/ca-ES.json +++ b/src/locales/ca-ES.json @@ -54,6 +54,7 @@ "veryLarge": "Molt gran", "solid": "Sòlid", "hachure": "Ratlletes", + "zigzag": "", "crossHatch": "Ratlletes creuades", "thin": "Fi", "bold": "Negreta", diff --git a/src/locales/cs-CZ.json b/src/locales/cs-CZ.json index d57a8837d..d039a78a2 100644 --- a/src/locales/cs-CZ.json +++ b/src/locales/cs-CZ.json @@ -54,6 +54,7 @@ "veryLarge": "Velmi velké", "solid": "Plný", "hachure": "", + "zigzag": "", "crossHatch": "", "thin": "Tenký", "bold": "Tlustý", diff --git a/src/locales/da-DK.json b/src/locales/da-DK.json index c8b5ad6e3..4d74ab80f 100644 --- a/src/locales/da-DK.json +++ b/src/locales/da-DK.json @@ -54,6 +54,7 @@ "veryLarge": "Meget stor", "solid": "Solid", "hachure": "Skravering", + "zigzag": "", "crossHatch": "Krydsskravering", "thin": "Tynd", "bold": "Fed", diff --git a/src/locales/de-DE.json b/src/locales/de-DE.json index bdf30a371..86b168ae5 100644 --- a/src/locales/de-DE.json +++ b/src/locales/de-DE.json @@ -54,6 +54,7 @@ "veryLarge": "Sehr groß", "solid": "Deckend", "hachure": "Schraffiert", + "zigzag": "Zickzack", "crossHatch": "Kreuzschraffiert", "thin": "Dünn", "bold": "Fett", diff --git a/src/locales/el-GR.json b/src/locales/el-GR.json index 888c39568..f4e0cfcaa 100644 --- a/src/locales/el-GR.json +++ b/src/locales/el-GR.json @@ -54,6 +54,7 @@ "veryLarge": "Πολύ μεγάλο", "solid": "Συμπαγής", "hachure": "Εκκόλαψη", + "zigzag": "", "crossHatch": "Διασταυρούμενη εκκόλαψη", "thin": "Λεπτή", "bold": "Έντονη", diff --git a/src/locales/es-ES.json b/src/locales/es-ES.json index 67a110293..c345c5f83 100644 --- a/src/locales/es-ES.json +++ b/src/locales/es-ES.json @@ -54,6 +54,7 @@ "veryLarge": "Muy grande", "solid": "Sólido", "hachure": "Folleto", + "zigzag": "Zigzag", "crossHatch": "Rayado transversal", "thin": "Fino", "bold": "Grueso", @@ -207,8 +208,8 @@ "collabSaveFailed": "No se pudo guardar en la base de datos del backend. Si los problemas persisten, debería guardar su archivo localmente para asegurarse de que no pierde su trabajo.", "collabSaveFailed_sizeExceeded": "No se pudo guardar en la base de datos del backend, el lienzo parece ser demasiado grande. Debería guardar el archivo localmente para asegurarse de que no pierde su trabajo.", "brave_measure_text_error": { - "start": "", - "aggressive_block_fingerprint": "", + "start": "Parece que estás usando el navegador Brave", + "aggressive_block_fingerprint": "Bloquear huellas dactilares agresivamente", "setting_enabled": "ajuste activado", "break": "Esto podría resultar en romper los", "text_elements": "Elementos de texto", @@ -319,8 +320,8 @@ "doubleClick": "doble clic", "drag": "arrastrar", "editor": "Editor", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Editar puntos de línea/flecha", + "editText": "Editar texto / añadir etiqueta", "github": "¿Ha encontrado un problema? Envíelo", "howto": "Siga nuestras guías", "or": "o", diff --git a/src/locales/eu-ES.json b/src/locales/eu-ES.json index 1aec330cb..9c5f14fac 100644 --- a/src/locales/eu-ES.json +++ b/src/locales/eu-ES.json @@ -54,6 +54,7 @@ "veryLarge": "Oso handia", "solid": "Solidoa", "hachure": "Itzalduna", + "zigzag": "", "crossHatch": "Marraduna", "thin": "Mehea", "bold": "Lodia", diff --git a/src/locales/fa-IR.json b/src/locales/fa-IR.json index 44cf7ae00..a22ad86a9 100644 --- a/src/locales/fa-IR.json +++ b/src/locales/fa-IR.json @@ -54,6 +54,7 @@ "veryLarge": "بسیار بزرگ", "solid": "توپر", "hachure": "هاشور", + "zigzag": "", "crossHatch": "هاشور متقاطع", "thin": "نازک", "bold": "ضخیم", diff --git a/src/locales/fi-FI.json b/src/locales/fi-FI.json index e0701f2d2..403bf0073 100644 --- a/src/locales/fi-FI.json +++ b/src/locales/fi-FI.json @@ -54,6 +54,7 @@ "veryLarge": "Erittäin suuri", "solid": "Yhtenäinen", "hachure": "Vinoviivoitus", + "zigzag": "", "crossHatch": "Ristiviivoitus", "thin": "Ohut", "bold": "Lihavoitu", diff --git a/src/locales/fr-FR.json b/src/locales/fr-FR.json index 49135c3b6..406a11a16 100644 --- a/src/locales/fr-FR.json +++ b/src/locales/fr-FR.json @@ -54,6 +54,7 @@ "veryLarge": "Très grande", "solid": "Solide", "hachure": "Hachures", + "zigzag": "", "crossHatch": "Hachures croisées", "thin": "Fine", "bold": "Épaisse", @@ -319,8 +320,8 @@ "doubleClick": "double-clic", "drag": "glisser", "editor": "Éditeur", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Modifier les points de ligne/flèche", + "editText": "Modifier le texte / ajouter un libellé", "github": "Problème trouvé ? Soumettre", "howto": "Suivez nos guides", "or": "ou", diff --git a/src/locales/gl-ES.json b/src/locales/gl-ES.json index 5571f3f15..53ae05d6b 100644 --- a/src/locales/gl-ES.json +++ b/src/locales/gl-ES.json @@ -54,6 +54,7 @@ "veryLarge": "Moi grande", "solid": "Sólido", "hachure": "Folleto", + "zigzag": "", "crossHatch": "Raiado transversal", "thin": "Estreito", "bold": "Groso", diff --git a/src/locales/he-IL.json b/src/locales/he-IL.json index 810fc1776..4cd8c1140 100644 --- a/src/locales/he-IL.json +++ b/src/locales/he-IL.json @@ -54,6 +54,7 @@ "veryLarge": "גדול מאוד", "solid": "מוצק", "hachure": "קווים מקבילים קצרים להצגת כיוון וחדות שיפוע במפה", + "zigzag": "", "crossHatch": "קווים מוצלבים שתי וערב", "thin": "דק", "bold": "מודגש", diff --git a/src/locales/hi-IN.json b/src/locales/hi-IN.json index 77d6dae2d..d9462e78b 100644 --- a/src/locales/hi-IN.json +++ b/src/locales/hi-IN.json @@ -54,6 +54,7 @@ "veryLarge": "बहुत बड़ा", "solid": "दृढ़", "hachure": "हैशूर", + "zigzag": "तेढ़ी मेढ़ी", "crossHatch": "क्रॉस हैच", "thin": "पतला", "bold": "मोटा", diff --git a/src/locales/hu-HU.json b/src/locales/hu-HU.json index d514520ed..5dc19945b 100644 --- a/src/locales/hu-HU.json +++ b/src/locales/hu-HU.json @@ -54,6 +54,7 @@ "veryLarge": "Nagyon nagy", "solid": "Kitöltött", "hachure": "Vonalkázott", + "zigzag": "", "crossHatch": "Keresztcsíkozott", "thin": "Vékony", "bold": "Félkövér", diff --git a/src/locales/id-ID.json b/src/locales/id-ID.json index 01b510fcd..eb5d8df71 100644 --- a/src/locales/id-ID.json +++ b/src/locales/id-ID.json @@ -54,6 +54,7 @@ "veryLarge": "Sangat besar", "solid": "Padat", "hachure": "Garis-garis", + "zigzag": "", "crossHatch": "Asiran silang", "thin": "Lembut", "bold": "Tebal", diff --git a/src/locales/it-IT.json b/src/locales/it-IT.json index 8380fd8e5..c31462ce2 100644 --- a/src/locales/it-IT.json +++ b/src/locales/it-IT.json @@ -54,6 +54,7 @@ "veryLarge": "Molto grande", "solid": "Pieno", "hachure": "Tratteggio obliquo", + "zigzag": "Zig zag", "crossHatch": "Tratteggio incrociato", "thin": "Sottile", "bold": "Grassetto", @@ -319,7 +320,7 @@ "doubleClick": "doppio-click", "drag": "trascina", "editor": "Editor", - "editLineArrowPoints": "", + "editLineArrowPoints": "Modifica punti linea/freccia", "editText": "Modifica testo / aggiungi etichetta", "github": "Trovato un problema? Segnalalo", "howto": "Segui le nostre guide", diff --git a/src/locales/ja-JP.json b/src/locales/ja-JP.json index 53333aea3..a457b1dfe 100644 --- a/src/locales/ja-JP.json +++ b/src/locales/ja-JP.json @@ -54,6 +54,7 @@ "veryLarge": "特大", "solid": "ベタ塗り", "hachure": "斜線", + "zigzag": "", "crossHatch": "網掛け", "thin": "細", "bold": "太字", diff --git a/src/locales/kab-KAB.json b/src/locales/kab-KAB.json index ba6a3de7e..62c6071c4 100644 --- a/src/locales/kab-KAB.json +++ b/src/locales/kab-KAB.json @@ -54,6 +54,7 @@ "veryLarge": "Meqqer aṭas", "solid": "Aččuran", "hachure": "Azerreg", + "zigzag": "", "crossHatch": "Azerreg anmidag", "thin": "Arqaq", "bold": "Azuran", diff --git a/src/locales/kk-KZ.json b/src/locales/kk-KZ.json index 97a9063fa..38acace0e 100644 --- a/src/locales/kk-KZ.json +++ b/src/locales/kk-KZ.json @@ -54,6 +54,7 @@ "veryLarge": "Өте үлкен", "solid": "", "hachure": "", + "zigzag": "", "crossHatch": "", "thin": "", "bold": "", diff --git a/src/locales/ko-KR.json b/src/locales/ko-KR.json index f170e4cbf..aa4647f28 100644 --- a/src/locales/ko-KR.json +++ b/src/locales/ko-KR.json @@ -54,6 +54,7 @@ "veryLarge": "매우 크게", "solid": "단색", "hachure": "평행선", + "zigzag": "지그재그", "crossHatch": "교차선", "thin": "얇게", "bold": "굵게", @@ -256,7 +257,7 @@ "resize": "SHIFT 키를 누르면서 조정하면 크기의 비율이 제한됩니다.\nALT를 누르면서 조정하면 중앙을 기준으로 크기를 조정합니다.", "resizeImage": "SHIFT를 눌러서 자유롭게 크기를 변경하거나,\nALT를 눌러서 중앙을 고정하고 크기를 변경하기", "rotate": "SHIFT 키를 누르면서 회전하면 각도를 제한할 수 있습니다.", - "lineEditor_info": "포인트를 편집하려면 Ctrl/Cmd을 누르고 더블 클릭을 하거나 Ctrl/Cmd + Enter를 누르세요", + "lineEditor_info": "꼭짓점을 수정하려면 CtrlOrCmd 키를 누르고 더블 클릭을 하거나 CtrlOrCmd + Enter를 누르세요.", "lineEditor_pointSelected": "Delete 키로 꼭짓점을 제거하거나,\nCtrlOrCmd+D 로 복제하거나, 드래그 해서 이동시키기", "lineEditor_nothingSelected": "꼭짓점을 선택해서 수정하거나 (SHIFT를 눌러서 여러개 선택),\nAlt를 누르고 클릭해서 새로운 꼭짓점 추가하기", "placeImage": "클릭해서 이미지를 배치하거나, 클릭하고 드래그해서 사이즈를 조정하기", @@ -319,8 +320,8 @@ "doubleClick": "더블 클릭", "drag": "드래그", "editor": "에디터", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "직선 / 화살표 꼭짓점 수정", + "editText": "텍스트 수정 / 라벨 추가", "github": "문제 제보하기", "howto": "가이드 참고하기", "or": "또는", @@ -382,8 +383,8 @@ }, "publishSuccessDialog": { "title": "라이브러리 제출됨", - "content": "{{authorName}}님 감사합니다. 당신의 라이브러리가 심사를 위해 제출되었습니다. 진행 상황을 다음의 링크에서 확인할 수 있습니다.", - "link": "여기" + "content": "{{authorName}}님 감사합니다. 당신의 라이브러리가 심사를 위해 제출되었습니다. 진행 상황을", + "link": "여기에서 확인하실 수 있습니다." }, "confirmDialog": { "resetLibrary": "라이브러리 리셋", diff --git a/src/locales/ku-TR.json b/src/locales/ku-TR.json index 76b5086e8..4fbf60492 100644 --- a/src/locales/ku-TR.json +++ b/src/locales/ku-TR.json @@ -1,7 +1,7 @@ { "labels": { "paste": "دانانەوە", - "pasteAsPlaintext": "", + "pasteAsPlaintext": "دایبنێ وەک دەقی سادە", "pasteCharts": "دانانەوەی خشتەکان", "selectAll": "دیاریکردنی هەموو", "multiSelect": "زیادکردنی بۆ دیاریکراوەکان", @@ -54,6 +54,7 @@ "veryLarge": "زۆر گه‌وره‌", "solid": "سادە", "hachure": "هاچور", + "zigzag": "زیگزاگ", "crossHatch": "کرۆس هاتچ", "thin": "تەنک", "bold": "تۆخ", @@ -110,7 +111,7 @@ "increaseFontSize": "زایدکردنی قەبارەی فۆنت", "unbindText": "دەقەکە جیابکەرەوە", "bindText": "دەقەکە ببەستەوە بە کۆنتەینەرەکەوە", - "createContainerFromText": "", + "createContainerFromText": "دەق لە چوارچێوەیەکدا بپێچە", "link": { "edit": "دەستکاریکردنی بەستەر", "create": "دروستکردنی بەستەر", @@ -194,7 +195,7 @@ "resetLibrary": "ئەمە کتێبخانەکەت خاوێن دەکاتەوە. ئایا دڵنیایت?", "removeItemsFromsLibrary": "سڕینەوەی {{count}} ئایتم(ەکان) لە کتێبخانە؟", "invalidEncryptionKey": "کلیلی رەمزاندن دەبێت لە 22 پیت بێت. هاوکاری ڕاستەوخۆ لە کارخراوە.", - "collabOfflineWarning": "" + "collabOfflineWarning": "هێڵی ئینتەرنێت بەردەست نییە.\n گۆڕانکارییەکانت سەیڤ ناکرێن!" }, "errors": { "unsupportedFileType": "جۆری فایلی پشتگیری نەکراو.", @@ -204,22 +205,22 @@ "invalidSVGString": "ئێس ڤی جی نادروستە.", "cannotResolveCollabServer": "ناتوانێت پەیوەندی بکات بە سێرڤەری کۆلاب. تکایە لاپەڕەکە دووبارە باربکەوە و دووبارە هەوڵ بدەوە.", "importLibraryError": "نەیتوانی کتێبخانە بار بکات", - "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "", + "collabSaveFailed": "نەتوانرا لە بنکەدراوەی ڕاژەدا پاشەکەوت بکرێت. ئەگەر کێشەکان بەردەوام بوون، پێویستە فایلەکەت لە ناوخۆدا هەڵبگریت بۆ ئەوەی دڵنیا بیت کە کارەکانت لەدەست نادەیت.", + "collabSaveFailed_sizeExceeded": "نەتوانرا لە بنکەدراوەی ڕاژەدا پاشەکەوت بکرێت، پێدەچێت تابلۆکە زۆر گەورە بێت. پێویستە فایلەکە لە ناوخۆدا هەڵبگریت بۆ ئەوەی دڵنیا بیت کە کارەکانت لەدەست نادەیت.", "brave_measure_text_error": { - "start": "", - "aggressive_block_fingerprint": "", - "setting_enabled": "", - "break": "", - "text_elements": "", - "in_your_drawings": "", - "strongly_recommend": "", - "steps": "", - "how": "", - "disable_setting": "", - "issue": "", - "write": "", - "discord": "" + "start": "پێدەچێت وێبگەڕی Brave بەکاربهێنیت لەگەڵ", + "aggressive_block_fingerprint": "بلۆککردنی Fingerprinting بەشێوەیەکی توندوتیژانە", + "setting_enabled": "ڕێکخستن چالاک کراوە", + "break": "ئەمە دەکرێت ببێتە هۆی تێکدانی", + "text_elements": "دانە دەقییەکان", + "in_your_drawings": "لە وێنەکێشانەکانتدا", + "strongly_recommend": "بە توندی پێشنیار دەکەین ئەم ڕێکخستنە لەکاربخەیت. دەتوانیت بڕۆیت بە دوای", + "steps": "ئەم هەنگاوانەدا", + "how": "بۆ ئەوەی ئەنجامی بدەیت", + "disable_setting": " ئەگەر لەکارخستنی ئەم ڕێکخستنە پیشاندانی توخمەکانی دەق چاک نەکاتەوە، تکایە هەڵبستە بە کردنەوەی", + "issue": "کێشەیەک", + "write": "لەسەر گیتهەبەکەمان، یان بۆمان بنوسە لە", + "discord": "دیسکۆرد" } }, "toolBar": { @@ -237,7 +238,7 @@ "penMode": "شێوازی قەڵەم - دەست لێدان ڕابگرە", "link": "زیادکردن/ نوێکردنەوەی لینک بۆ شێوەی دیاریکراو", "eraser": "سڕەر", - "hand": "" + "hand": "دەست (ئامرازی پانکردن)" }, "headings": { "canvasActions": "کردارەکانی تابلۆ", @@ -245,7 +246,7 @@ "shapes": "شێوەکان" }, "hints": { - "canvasPanning": "", + "canvasPanning": "بۆ جوڵاندنی تابلۆ، ویلی ماوسەکەت یان دوگمەی سپەیس بگرە لەکاتی ڕاکێشاندە، یانیش ئامرازی دەستەکە بەکاربهێنە", "linearElement": "کرتە بکە بۆ دەستپێکردنی چەند خاڵێک، ڕایبکێشە بۆ یەک هێڵ", "freeDraw": "کرتە بکە و ڕایبکێشە، کاتێک تەواو بوویت دەست هەڵگرە", "text": "زانیاری: هەروەها دەتوانیت دەق زیادبکەیت بە دوو کرتەکردن لە هەر شوێنێک لەگەڵ ئامڕازی دەستنیشانکردن", @@ -256,7 +257,7 @@ "resize": "دەتوانیت ڕێژەکان سنووردار بکەیت بە ڕاگرتنی SHIFT لەکاتی گۆڕینی قەبارەدا،\nALT ڕابگرە بۆ گۆڕینی قەبارە لە ناوەندەوە", "resizeImage": "دەتوانیت بە ئازادی قەبارە بگۆڕیت بە ڕاگرتنی SHIFT،\nALT ڕابگرە بۆ گۆڕینی قەبارە لە ناوەندەوە", "rotate": "دەتوانیت گۆشەکان سنووردار بکەیت بە ڕاگرتنی SHIFT لەکاتی سوڕانەوەدا", - "lineEditor_info": "", + "lineEditor_info": "یان Ctrl یان Cmd بگرە و دوانە کلیک بکە یانیش پەنجە بنێ بە Ctrl یان Cmd + ئینتەر بۆ دەستکاریکردنی خاڵەکان", "lineEditor_pointSelected": "بۆ لابردنی خاڵەکان Delete دابگرە، Ctrl Cmd+D بکە بۆ لەبەرگرتنەوە، یان بۆ جووڵە ڕاکێشان بکە", "lineEditor_nothingSelected": "خاڵێک هەڵبژێرە بۆ دەستکاریکردن (SHIFT ڕابگرە بۆ هەڵبژاردنی چەندین)،\nیان Alt ڕابگرە و کلیک بکە بۆ زیادکردنی خاڵە نوێیەکان", "placeImage": "کلیک بکە بۆ دانانی وێنەکە، یان کلیک بکە و ڕایبکێشە بۆ ئەوەی قەبارەکەی بە دەستی دابنێیت", @@ -264,7 +265,7 @@ "bindTextToElement": "بۆ زیادکردنی دەق enter بکە", "deepBoxSelect": "CtrlOrCmd ڕابگرە بۆ هەڵبژاردنی قووڵ، و بۆ ڕێگریکردن لە ڕاکێشان", "eraserRevert": "بۆ گەڕاندنەوەی ئەو توخمانەی کە بۆ سڕینەوە نیشانە کراون، Alt ڕابگرە", - "firefox_clipboard_write": "" + "firefox_clipboard_write": "ئەم تایبەتمەندییە بە ئەگەرێکی زۆرەوە دەتوانرێت چالاک بکرێت بە ڕێکخستنی ئاڵای \"dom.events.asyncClipboard.clipboardItem\" بۆ \"true\". بۆ گۆڕینی ئاڵاکانی وێبگەڕ لە فایەرفۆکسدا، سەردانی لاپەڕەی \"about:config\" بکە." }, "canvasError": { "cannotShowPreview": "ناتوانرێ پێشبینین پیشان بدرێت", @@ -319,8 +320,8 @@ "doubleClick": "دوو گرتە", "drag": "راکێشان", "editor": "دەستکاریکەر", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "دەستکاری خاڵەکانی هێڵ/تیر بکە", + "editText": "دەستکاری دەق بکە / لەیبڵێک زیاد بکە", "github": "کێشەیەکت دۆزیەوە؟ پێشکەشکردن", "howto": "شوێن ڕینماییەکانمان بکەوە", "or": "یان", @@ -334,8 +335,8 @@ "zoomToFit": "زووم بکە بۆ ئەوەی لەگەڵ هەموو توخمەکاندا بگونجێت", "zoomToSelection": "زووم بکە بۆ دەستنیشانکراوەکان", "toggleElementLock": "قفڵ/کردنەوەی دەستنیشانکراوەکان", - "movePageUpDown": "", - "movePageLeftRight": "" + "movePageUpDown": "لاپەڕەکە بجوڵێنە بۆ سەرەوە/خوارەوە", + "movePageLeftRight": "لاپەڕەکە بجوڵێنە بۆ چەپ/ڕاست" }, "clearCanvasDialog": { "title": "تابلۆکە خاوێن بکەرەوە" @@ -417,7 +418,7 @@ "fileSavedToFilename": "هەڵگیراوە بۆ {filename}", "canvas": "تابلۆ", "selection": "دەستنیشانکراوەکان", - "pasteAsSingleElement": "" + "pasteAsSingleElement": "بۆ دانانەوە وەکو یەک توخم یان دانانەوە بۆ نێو دەسکاریکەرێکی دەق کە بوونی هەیە {{shortcut}} بەکاربهێنە" }, "colors": { "ffffff": "سپی", @@ -468,15 +469,15 @@ }, "welcomeScreen": { "app": { - "center_heading": "", - "center_heading_plus": "", - "menuHint": "" + "center_heading": "هەموو داتاکانت لە ناوخۆی وێنگەڕەکەتدا پاشەکەوت کراوە.", + "center_heading_plus": "ویستت بڕۆیت بۆ Excalidraw+?", + "menuHint": "هەناردەکردن، ڕێکخستنەکان، زمانەکان، ..." }, "defaults": { - "menuHint": "", - "center_heading": "", - "toolbarHint": "", - "helpHint": "" + "menuHint": "هەناردەکردن، ڕێکخستنەکان، و زیاتر...", + "center_heading": "دایاگرامەکان. ئاسان. کراون.", + "toolbarHint": "ئامرازێک هەڵبگرە و دەستبکە بە کێشان!", + "helpHint": "قەدبڕەکان و یارمەتی" } } } diff --git a/src/locales/lt-LT.json b/src/locales/lt-LT.json index d80739f09..1c18c2729 100644 --- a/src/locales/lt-LT.json +++ b/src/locales/lt-LT.json @@ -54,6 +54,7 @@ "veryLarge": "Labai didelis", "solid": "", "hachure": "", + "zigzag": "", "crossHatch": "", "thin": "Plonas", "bold": "Pastorintas", diff --git a/src/locales/lv-LV.json b/src/locales/lv-LV.json index 4a311f7cd..bc8a3a678 100644 --- a/src/locales/lv-LV.json +++ b/src/locales/lv-LV.json @@ -54,6 +54,7 @@ "veryLarge": "Ļoti liels", "solid": "Pilns", "hachure": "Svītrots", + "zigzag": "Zigzaglīnija", "crossHatch": "Šķērssvītrots", "thin": "Šaurs", "bold": "Trekns", @@ -110,7 +111,7 @@ "increaseFontSize": "Palielināt fonta izmēru", "unbindText": "Atdalīt tekstu", "bindText": "Piesaistīt tekstu figūrai", - "createContainerFromText": "", + "createContainerFromText": "Ietilpināt tekstu figurā", "link": { "edit": "Rediģēt saiti", "create": "Izveidot saiti", @@ -194,7 +195,7 @@ "resetLibrary": "Šī funkcija iztukšos bibliotēku. Vai turpināt?", "removeItemsFromsLibrary": "Vai izņemt {{count}} vienumu(s) no bibliotēkas?", "invalidEncryptionKey": "Šifrēšanas atslēgai jābūt 22 simbolus garai. Tiešsaistes sadarbība ir izslēgta.", - "collabOfflineWarning": "" + "collabOfflineWarning": "Nav pieejams interneta pieslēgums.\nJūsu izmaiņas netiks saglabātas!" }, "errors": { "unsupportedFileType": "Neatbalstīts datnes veids.", @@ -207,19 +208,19 @@ "collabSaveFailed": "Darbs nav saglabāts datubāzē. Ja problēma turpinās, saglabājiet datni lokālajā krātuvē, lai nodrošinātos pret darba pazaudēšanu.", "collabSaveFailed_sizeExceeded": "Darbs nav saglabāts datubāzē, šķiet, ka tāfele ir pārāk liela. Saglabājiet datni lokālajā krātuvē, lai nodrošinātos pret darba pazaudēšanu.", "brave_measure_text_error": { - "start": "", - "aggressive_block_fingerprint": "", - "setting_enabled": "", - "break": "", - "text_elements": "", - "in_your_drawings": "", - "strongly_recommend": "", - "steps": "", - "how": "", - "disable_setting": "", - "issue": "", - "write": "", - "discord": "" + "start": "Izskatās, ka izmanto Brave interneta plārlūku ar ieslēgtu", + "aggressive_block_fingerprint": "Aggressively Block Fingerprinting", + "setting_enabled": "ieslēgtu iestatījumu", + "break": "Tas var salauzt", + "text_elements": "Teksta elementus", + "in_your_drawings": "tavos zīmējumos", + "strongly_recommend": "Mēs iesakām izslēgt šo iestatījumu. Tu vari sekot", + "steps": "šiem soļiem", + "how": "kā to izdarīt", + "disable_setting": " Ja šī iestatījuma izslēgšana neatrisina teksta elementu attēlošanu, tad, lūdzu, atver", + "issue": "problēmu", + "write": "mūsu GitHub vai raksti mums", + "discord": "Discord" } }, "toolBar": { @@ -237,7 +238,7 @@ "penMode": "Pildspalvas režīms – novērst pieskaršanos", "link": "Pievienot/rediģēt atlasītās figūras saiti", "eraser": "Dzēšgumija", - "hand": "" + "hand": "Roka (panoramēšanas rīks)" }, "headings": { "canvasActions": "Tāfeles darbības", @@ -245,7 +246,7 @@ "shapes": "Formas" }, "hints": { - "canvasPanning": "", + "canvasPanning": "Lai bīdītu tāfeli, turiet nospiestu ritināšanas vai atstarpes taustiņu, vai izmanto rokas rīku", "linearElement": "Klikšķiniet, lai sāktu zīmēt vairākus punktus; velciet, lai zīmētu līniju", "freeDraw": "Spiediet un velciet; atlaidiet, kad pabeidzat", "text": "Ieteikums: lai pievienotu tekstu, varat arī jebkur dubultklikšķināt ar atlases rīku", @@ -264,7 +265,7 @@ "bindTextToElement": "Spiediet ievades taustiņu, lai pievienotu tekstu", "deepBoxSelect": "Turient nospiestu Ctrl vai Cmd, lai atlasītu dziļumā un lai nepieļautu objektu pavilkšanu", "eraserRevert": "Turiet Alt, lai noņemtu elementus no dzēsšanas atlases", - "firefox_clipboard_write": "" + "firefox_clipboard_write": "Šis iestatījums var tikt ieslēgts ar \"dom.events.asyncClipboard.clipboardItem\" marķieri pārslēgtu uz \"true\". Lai mainītu pārlūka marķierus Firefox, apmeklē \"about:config\" lapu." }, "canvasError": { "cannotShowPreview": "Nevar rādīt priekšskatījumu", @@ -319,8 +320,8 @@ "doubleClick": "dubultklikšķis", "drag": "vilkt", "editor": "Redaktors", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Rediģēt līniju/bultu punktus", + "editText": "Rediģēt tekstu/pievienot birku", "github": "Sastapāt kļūdu? Ziņot", "howto": "Sekojiet mūsu instrukcijām", "or": "vai", @@ -468,15 +469,15 @@ }, "welcomeScreen": { "app": { - "center_heading": "", - "center_heading_plus": "", - "menuHint": "" + "center_heading": "Visi jūsu dati tiek glabāti uz vietas jūsu pārlūkā.", + "center_heading_plus": "Vai tā vietā vēlies doties uz Excalidraw+?", + "menuHint": "Eksportēšana, iestatījumi, valodas..." }, "defaults": { - "menuHint": "", - "center_heading": "", - "toolbarHint": "", - "helpHint": "" + "menuHint": "Eksportēšana, iestatījumi un vēl...", + "center_heading": "Diagrammas. Izveidotas. Vienkārši.", + "toolbarHint": "Izvēlies rīku un sāc zīmēt!", + "helpHint": "Īsceļi un palīdzība" } } } diff --git a/src/locales/mr-IN.json b/src/locales/mr-IN.json index 4f58009c9..346ae5603 100644 --- a/src/locales/mr-IN.json +++ b/src/locales/mr-IN.json @@ -54,6 +54,7 @@ "veryLarge": "फार मोठं", "solid": "भरीव", "hachure": "हैशूर रेखांकन", + "zigzag": "वाकडी तिकड़ी", "crossHatch": "आडव्या रेघा", "thin": "पातळ", "bold": "जाड", diff --git a/src/locales/my-MM.json b/src/locales/my-MM.json index efc874218..437e9d13b 100644 --- a/src/locales/my-MM.json +++ b/src/locales/my-MM.json @@ -54,6 +54,7 @@ "veryLarge": "ပိုကြီး", "solid": "အပြည့်", "hachure": "မျဉ်းစောင်း", + "zigzag": "", "crossHatch": "ဇကာကွက်", "thin": "ပါး", "bold": "ထူ", diff --git a/src/locales/nb-NO.json b/src/locales/nb-NO.json index 27e717d2a..7a2e72c55 100644 --- a/src/locales/nb-NO.json +++ b/src/locales/nb-NO.json @@ -54,6 +54,7 @@ "veryLarge": "Svært stor", "solid": "Helfarge", "hachure": "Skravert", + "zigzag": "Sikk-sakk", "crossHatch": "Krysskravert", "thin": "Tynn", "bold": "Tykk", diff --git a/src/locales/nl-NL.json b/src/locales/nl-NL.json index 7c2bb105b..62baedf83 100644 --- a/src/locales/nl-NL.json +++ b/src/locales/nl-NL.json @@ -54,6 +54,7 @@ "veryLarge": "Zeer groot", "solid": "Ingekleurd", "hachure": "Arcering", + "zigzag": "", "crossHatch": "Tweemaal gearceerd", "thin": "Dun", "bold": "Vet", diff --git a/src/locales/nn-NO.json b/src/locales/nn-NO.json index 1733b84c4..49333b910 100644 --- a/src/locales/nn-NO.json +++ b/src/locales/nn-NO.json @@ -54,6 +54,7 @@ "veryLarge": "Svært stor", "solid": "Solid", "hachure": "Skravert", + "zigzag": "", "crossHatch": "Krysskravert", "thin": "Tynn", "bold": "Tjukk", diff --git a/src/locales/oc-FR.json b/src/locales/oc-FR.json index a9ca70a84..cae6682df 100644 --- a/src/locales/oc-FR.json +++ b/src/locales/oc-FR.json @@ -54,6 +54,7 @@ "veryLarge": "Gradassa", "solid": "Solide", "hachure": "Raia", + "zigzag": "", "crossHatch": "Raia crosada", "thin": "Fin", "bold": "Espés", diff --git a/src/locales/pa-IN.json b/src/locales/pa-IN.json index 31c11ceb8..2b7c66a33 100644 --- a/src/locales/pa-IN.json +++ b/src/locales/pa-IN.json @@ -54,6 +54,7 @@ "veryLarge": "ਬਹੁਤ ਵੱਡਾ", "solid": "ਠੋਸ", "hachure": "ਤਿਰਛੀਆਂ ਗਰਿੱਲਾਂ", + "zigzag": "", "crossHatch": "ਜਾਲੀ", "thin": "ਪਤਲੀ", "bold": "ਮੋਟੀ", diff --git a/src/locales/percentages.json b/src/locales/percentages.json index b28b6c259..b12928698 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -1,17 +1,17 @@ { - "ar-SA": 89, + "ar-SA": 88, "bg-BG": 52, "bn-BD": 57, - "ca-ES": 96, - "cs-CZ": 72, + "ca-ES": 95, + "cs-CZ": 71, "da-DK": 31, "de-DE": 100, "el-GR": 98, "en": 100, - "es-ES": 99, + "es-ES": 100, "eu-ES": 99, "fa-IR": 91, - "fi-FI": 96, + "fi-FI": 95, "fr-FR": 99, "gl-ES": 99, "he-IL": 99, @@ -19,35 +19,35 @@ "hu-HU": 85, "id-ID": 98, "it-IT": 99, - "ja-JP": 97, + "ja-JP": 96, "kab-KAB": 93, "kk-KZ": 19, - "ko-KR": 99, - "ku-TR": 91, + "ko-KR": 100, + "ku-TR": 100, "lt-LT": 61, - "lv-LV": 93, + "lv-LV": 100, "mr-IN": 100, - "my-MM": 40, + "my-MM": 39, "nb-NO": 100, "nl-NL": 92, - "nn-NO": 86, + "nn-NO": 85, "oc-FR": 94, "pa-IN": 79, "pl-PL": 87, - "pt-BR": 96, - "pt-PT": 99, + "pt-BR": 95, + "pt-PT": 100, "ro-RO": 100, - "ru-RU": 96, + "ru-RU": 100, "si-LK": 8, "sk-SK": 99, "sl-SI": 100, - "sv-SE": 99, + "sv-SE": 100, "ta-IN": 90, "th-TH": 39, - "tr-TR": 98, - "uk-UA": 93, + "tr-TR": 97, + "uk-UA": 92, "vi-VN": 52, "zh-CN": 99, - "zh-HK": 25, + "zh-HK": 24, "zh-TW": 100 } diff --git a/src/locales/pl-PL.json b/src/locales/pl-PL.json index 1abaa038f..797d88fa1 100644 --- a/src/locales/pl-PL.json +++ b/src/locales/pl-PL.json @@ -54,6 +54,7 @@ "veryLarge": "Bardzo duży", "solid": "Pełne", "hachure": "Linie", + "zigzag": "", "crossHatch": "Zakreślone", "thin": "Cienkie", "bold": "Pogrubione", diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index d790c5db5..12a1a5d46 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -54,6 +54,7 @@ "veryLarge": "Muito grande", "solid": "Sólido", "hachure": "Hachura", + "zigzag": "", "crossHatch": "Hachura cruzada", "thin": "Fino", "bold": "Espesso", diff --git a/src/locales/pt-PT.json b/src/locales/pt-PT.json index 7ce28f00f..947682311 100644 --- a/src/locales/pt-PT.json +++ b/src/locales/pt-PT.json @@ -54,6 +54,7 @@ "veryLarge": "Muito grande", "solid": "Sólido", "hachure": "Eclosão", + "zigzag": "ziguezague", "crossHatch": "Sombreado", "thin": "Fino", "bold": "Espesso", @@ -319,8 +320,8 @@ "doubleClick": "clique duplo", "drag": "arrastar", "editor": "Editor", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Editar pontos de linha/seta", + "editText": "Editar texto / adicionar etiqueta", "github": "Encontrou algum problema? Informe-nos", "howto": "Siga os nossos guias", "or": "ou", diff --git a/src/locales/ro-RO.json b/src/locales/ro-RO.json index a0e3b5883..611ed5676 100644 --- a/src/locales/ro-RO.json +++ b/src/locales/ro-RO.json @@ -54,6 +54,7 @@ "veryLarge": "Foarte mare", "solid": "Plină", "hachure": "Hașură", + "zigzag": "Zigzag", "crossHatch": "Hașură transversală", "thin": "Subțire", "bold": "Îngroșată", diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json index d4030897c..cda20347a 100644 --- a/src/locales/ru-RU.json +++ b/src/locales/ru-RU.json @@ -54,6 +54,7 @@ "veryLarge": "Очень большой", "solid": "Однотонная", "hachure": "Штрихованная", + "zigzag": "Зигзаг", "crossHatch": "Перекрестная", "thin": "Тонкая", "bold": "Жирная", @@ -110,7 +111,7 @@ "increaseFontSize": "Увеличить шрифт", "unbindText": "Отвязать текст", "bindText": "Привязать текст к контейнеру", - "createContainerFromText": "", + "createContainerFromText": "Поместить текст в контейнер", "link": { "edit": "Редактировать ссылку", "create": "Создать ссылку", @@ -207,19 +208,19 @@ "collabSaveFailed": "Не удалось сохранить в базу данных. Если проблема повторится, нужно будет сохранить файл локально, чтобы быть уверенным, что вы не потеряете вашу работу.", "collabSaveFailed_sizeExceeded": "Не удалось сохранить в базу данных. Похоже, что холст слишком большой. Нужно сохранить файл локально, чтобы быть уверенным, что вы не потеряете вашу работу.", "brave_measure_text_error": { - "start": "", - "aggressive_block_fingerprint": "", - "setting_enabled": "", - "break": "", - "text_elements": "", - "in_your_drawings": "", - "strongly_recommend": "", - "steps": "", - "how": "", - "disable_setting": "", - "issue": "", - "write": "", - "discord": "" + "start": "Похоже, вы используете браузер Brave с", + "aggressive_block_fingerprint": "Агрессивно блокировать фингерпринтинг", + "setting_enabled": "параметр включен", + "break": "Это может привести к поломке", + "text_elements": "Текстовых элементов", + "in_your_drawings": "в ваших рисунках", + "strongly_recommend": "Мы настоятельно рекомендуем отключить эту настройку. Вы можете выполнить", + "steps": "эти действия", + "how": "для отключения", + "disable_setting": " Если отключение этого параметра не исправит отображение текстовых элементов, пожалуйста, откройте", + "issue": "issue", + "write": "на нашем GitHub, или напишите нам в", + "discord": "Discord" } }, "toolBar": { @@ -319,8 +320,8 @@ "doubleClick": "двойной клик", "drag": "перетащить", "editor": "Редактор", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Редактировать концы линий/стрелок", + "editText": "Редактировать текст / добавить метку", "github": "Нашли проблему? Отправьте", "howto": "Следуйте нашим инструкциям", "or": "или", diff --git a/src/locales/si-LK.json b/src/locales/si-LK.json index b84ad567f..01f5bcac2 100644 --- a/src/locales/si-LK.json +++ b/src/locales/si-LK.json @@ -54,6 +54,7 @@ "veryLarge": "ඉතා විශාල", "solid": "විශාල", "hachure": "මධ්‍යම", + "zigzag": "", "crossHatch": "", "thin": "කෙට්ටු", "bold": "තද", diff --git a/src/locales/sk-SK.json b/src/locales/sk-SK.json index d6322ac1c..4bb6f0e76 100644 --- a/src/locales/sk-SK.json +++ b/src/locales/sk-SK.json @@ -54,6 +54,7 @@ "veryLarge": "Veľmi veľké", "solid": "Plná", "hachure": "Šrafovaná", + "zigzag": "", "crossHatch": "Mriežkovaná", "thin": "Tenká", "bold": "Hrubá", @@ -319,8 +320,8 @@ "doubleClick": "dvojklik", "drag": "potiahnutie", "editor": "Editovanie", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Editácia bodov čiary/šípky", + "editText": "Editácia textu / pridanie štítku", "github": "Objavili ste problém? Nahláste ho", "howto": "Postupujte podľa naších návodov", "or": "alebo", diff --git a/src/locales/sl-SI.json b/src/locales/sl-SI.json index 57199c813..dc073c0cb 100644 --- a/src/locales/sl-SI.json +++ b/src/locales/sl-SI.json @@ -54,6 +54,7 @@ "veryLarge": "Zelo velika", "solid": "Polno", "hachure": "Šrafura", + "zigzag": "Cikcak", "crossHatch": "Križno", "thin": "Tanko", "bold": "Krepko", diff --git a/src/locales/sv-SE.json b/src/locales/sv-SE.json index d0392b119..502c1bb1e 100644 --- a/src/locales/sv-SE.json +++ b/src/locales/sv-SE.json @@ -54,6 +54,7 @@ "veryLarge": "Mycket stor", "solid": "Solid", "hachure": "Skraffering", + "zigzag": "Sicksack", "crossHatch": "Skraffera med kors", "thin": "Tunn", "bold": "Fet", @@ -319,8 +320,8 @@ "doubleClick": "dubbelklicka", "drag": "dra", "editor": "Redigerare", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Redigera linje-/pilpunkter", + "editText": "Redigera text / lägg till etikett", "github": "Hittat ett problem? Rapportera", "howto": "Följ våra guider", "or": "eller", diff --git a/src/locales/ta-IN.json b/src/locales/ta-IN.json index 6dc865766..47c6e644b 100644 --- a/src/locales/ta-IN.json +++ b/src/locales/ta-IN.json @@ -54,6 +54,7 @@ "veryLarge": "மிகப் பெரிய", "solid": "திடமான", "hachure": "மலைக்குறிக்கோடு", + "zigzag": "", "crossHatch": "குறுக்குகதவு", "thin": "மெல்லிய", "bold": "பட்டை", diff --git a/src/locales/th-TH.json b/src/locales/th-TH.json index 2dcb9cb43..021c0ce97 100644 --- a/src/locales/th-TH.json +++ b/src/locales/th-TH.json @@ -54,6 +54,7 @@ "veryLarge": "ใหญ่มาก", "solid": "", "hachure": "", + "zigzag": "", "crossHatch": "", "thin": "บาง", "bold": "หนา", diff --git a/src/locales/tr-TR.json b/src/locales/tr-TR.json index 78dd9329a..8e1f2b4a0 100644 --- a/src/locales/tr-TR.json +++ b/src/locales/tr-TR.json @@ -54,6 +54,7 @@ "veryLarge": "Çok geniş", "solid": "Dolu", "hachure": "Taralı", + "zigzag": "", "crossHatch": "Çapraz-taralı", "thin": "İnce", "bold": "Kalın", diff --git a/src/locales/uk-UA.json b/src/locales/uk-UA.json index ed1a01e68..417e0a16a 100644 --- a/src/locales/uk-UA.json +++ b/src/locales/uk-UA.json @@ -54,6 +54,7 @@ "veryLarge": "Дуже великий", "solid": "Суцільна", "hachure": "Штриховка", + "zigzag": "", "crossHatch": "Перехресна штриховка", "thin": "Тонкий", "bold": "Жирний", diff --git a/src/locales/vi-VN.json b/src/locales/vi-VN.json index 887c32e3e..27fccfb53 100644 --- a/src/locales/vi-VN.json +++ b/src/locales/vi-VN.json @@ -54,6 +54,7 @@ "veryLarge": "Rất lớn", "solid": "Đặc", "hachure": "Nét gạch gạch", + "zigzag": "", "crossHatch": "Nét gạch chéo", "thin": "Mỏng", "bold": "In đậm", diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 5863f5ceb..18584cda7 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -54,6 +54,7 @@ "veryLarge": "加大", "solid": "实心", "hachure": "线条", + "zigzag": "", "crossHatch": "交叉线条", "thin": "细", "bold": "粗", @@ -319,8 +320,8 @@ "doubleClick": "双击", "drag": "拖动", "editor": "编辑器", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "编辑线条或箭头的点", + "editText": "添加或编辑文本", "github": "提交问题", "howto": "帮助文档", "or": "或", diff --git a/src/locales/zh-HK.json b/src/locales/zh-HK.json index bbf23f7f7..5cff35a5c 100644 --- a/src/locales/zh-HK.json +++ b/src/locales/zh-HK.json @@ -54,6 +54,7 @@ "veryLarge": "勁大", "solid": "實心", "hachure": "斜線", + "zigzag": "", "crossHatch": "交叉格仔", "thin": "幼", "bold": "粗", diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index f4462842c..25c9b0f57 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -54,6 +54,7 @@ "veryLarge": "特大", "solid": "實心", "hachure": "斜線筆觸", + "zigzag": "Z字形", "crossHatch": "交叉筆觸", "thin": "細", "bold": "粗", From b1311a407a636c87ee0ca326fd20599d0ce4ba9b Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 2 May 2023 12:49:11 +0530 Subject: [PATCH 058/451] fix: Revert add version tags to Docker build (#6540) Revert "build: Add version tags to Docker build (#6508)" This reverts commit 1815cf3213b1d19cb6aa1a54dabd969196a65a28. --- .github/workflows/publish-docker.yml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 3602bb660..a4a8a4c5f 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -12,24 +12,14 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 - - name: Docker meta - id: meta - uses: docker/metadata-action@v4 - with: - images: | - excalidraw/excalidraw - tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - name: Login to DockerHub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v3 with: context: . push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + tags: excalidraw/excalidraw:latest From e9cae918a7c83c577afb5f6385f6aba9d3544670 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Thu, 4 May 2023 19:33:31 +0200 Subject: [PATCH 059/451] feat: sidebar tabs support (#6213) * feat: Sidebar tabs support [wip] * tab trigger styling tweaks * add `:hover` & `:active` states * replace `@dwelle/tunnel-rat` with `tunnel-rat` * make stuff more explicit - remove `Sidebar.Header` fallback (host apps need to render manually), and stop tunneling it (render in place) - make `docked` state explicit - stop tunneling `Sidebar.TabTriggers` (render in place) * redesign sidebar / library as per latest spec * support no label on `Sidebar.Trigger` * add Sidebar `props.onStateChange` * style fixes * make `appState.isSidebarDocked` into a soft user preference * px -> rem & refactor * remove `props.renderSidebar` * update tests * remove * refactor * rename constants * tab triggers styling fixes * factor out library-related logic from generic sidebar trigger * change `props.onClose` to `onToggle` * rename `props.value` -> `props.tab` * add displayNames * allow HTMLAttributes on applicable compos * fix example App * more styling tweaks and fixes * fix not setting `dockable` * more style fixes * fix and align sidebar header button styling * make DefaultSidebar dockable on if host apps supplies `onDock` * stop `Sidebar.Trigger` hiding label on mobile this should be only the default sidebar trigger behavior, and for that we don't need to use `device` hook as we handle in CSS * fix `dockable` prop of defaultSidebar * remove extra `typescript` dep * remove `defaultTab` prop in favor of explicit `tab` value in `` and `toggleSidebar()`, to reduce API surface area and solve inconsistency of `appState.openSidebar.tab` not reflecting actual UI value if `defaultTab` was supported (without additional syncing logic which feels like the wrong solution). * remove `onToggle` in favor of `onStateChange` reducing API surface area * fix restore * comment no longer applies * reuse `Button` component in sidebar buttons * fix tests * split Sidebar sub-components into files * remove `props.dockable` in favor of `props.onDock` only * split tests * fix sidebar showing dock button if no `props.docked` supplied & add more tests * reorder and group sidebar tests * clarify * rename classes & dedupe css * refactor tests * update changelog * update changelog --------- Co-authored-by: barnabasmolnar --- package.json | 4 +- src/appState.ts | 8 +- src/components/App.tsx | 229 ++++--- src/components/Button.tsx | 12 +- src/components/ConfirmDialog.tsx | 7 +- src/components/DefaultSidebar.test.tsx | 144 +++++ src/components/DefaultSidebar.tsx | 118 ++++ src/components/Dialog.tsx | 2 +- src/components/HintViewer.tsx | 2 +- src/components/LayerUI.tsx | 137 +++-- src/components/LibraryButton.scss | 32 - src/components/LibraryButton.tsx | 57 -- src/components/LibraryMenu.scss | 72 +-- src/components/LibraryMenu.tsx | 212 ++----- src/components/LibraryMenuControlButtons.tsx | 33 + src/components/LibraryMenuHeaderContent.tsx | 65 +- src/components/LibraryMenuItems.scss | 4 +- src/components/LibraryMenuItems.tsx | 22 +- src/components/MobileMenu.tsx | 23 +- src/components/PasteChartDialog.tsx | 8 +- src/components/Sidebar/Sidebar.scss | 211 ++++--- src/components/Sidebar/Sidebar.test.tsx | 572 +++++++++--------- src/components/Sidebar/Sidebar.tsx | 358 +++++++---- src/components/Sidebar/SidebarHeader.tsx | 98 +-- src/components/Sidebar/SidebarTab.tsx | 18 + src/components/Sidebar/SidebarTabTrigger.tsx | 26 + src/components/Sidebar/SidebarTabTriggers.tsx | 16 + src/components/Sidebar/SidebarTabs.tsx | 36 ++ src/components/Sidebar/SidebarTrigger.scss | 34 ++ src/components/Sidebar/SidebarTrigger.tsx | 45 ++ src/components/Sidebar/common.ts | 34 +- src/components/context/tunnels.ts | 32 - .../dropdownMenu/DropdownMenuContent.tsx | 4 +- src/components/footer/Footer.tsx | 8 +- src/components/footer/FooterCenter.tsx | 8 +- src/components/hoc/withInternalFallback.tsx | 26 +- src/components/hoc/withUpstreamOverride.tsx | 63 -- src/components/main-menu/MainMenu.tsx | 8 +- .../welcome-screen/WelcomeScreen.Center.tsx | 8 +- .../welcome-screen/WelcomeScreen.Hints.tsx | 20 +- src/constants.ts | 7 + src/context/tunnels.ts | 36 ++ src/context/ui-appState.ts | 5 + src/css/styles.scss | 2 +- src/css/theme.scss | 6 + src/css/variables.module.scss | 18 +- src/data/library.ts | 22 +- src/data/restore.ts | 32 +- src/data/types.ts | 6 +- src/hooks/useOutsideClick.ts | 2 +- src/packages/excalidraw/CHANGELOG.md | 16 + src/packages/excalidraw/example/App.tsx | 51 +- src/packages/excalidraw/index.tsx | 6 +- .../__snapshots__/contextmenu.test.tsx.snap | 34 +- .../regressionTests.test.tsx.snap | 106 ++-- src/tests/data/restore.test.ts | 25 +- src/tests/library.test.tsx | 9 +- .../packages/__snapshots__/utils.test.ts.snap | 2 +- src/types.ts | 23 +- src/utils.ts | 20 +- yarn.lock | 159 ++++- 61 files changed, 1972 insertions(+), 1431 deletions(-) create mode 100644 src/components/DefaultSidebar.test.tsx create mode 100644 src/components/DefaultSidebar.tsx delete mode 100644 src/components/LibraryButton.scss delete mode 100644 src/components/LibraryButton.tsx create mode 100644 src/components/LibraryMenuControlButtons.tsx create mode 100644 src/components/Sidebar/SidebarTab.tsx create mode 100644 src/components/Sidebar/SidebarTabTrigger.tsx create mode 100644 src/components/Sidebar/SidebarTabTriggers.tsx create mode 100644 src/components/Sidebar/SidebarTabs.tsx create mode 100644 src/components/Sidebar/SidebarTrigger.scss create mode 100644 src/components/Sidebar/SidebarTrigger.tsx delete mode 100644 src/components/context/tunnels.ts delete mode 100644 src/components/hoc/withUpstreamOverride.tsx create mode 100644 src/context/tunnels.ts create mode 100644 src/context/ui-appState.ts diff --git a/package.json b/package.json index 5816786e3..57bdfe562 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ ] }, "dependencies": { - "@dwelle/tunnel-rat": "0.1.1", + "@radix-ui/react-tabs": "1.0.2", "@sentry/browser": "6.2.5", "@sentry/integrations": "6.2.5", "@testing-library/jest-dom": "5.16.2", @@ -51,7 +51,7 @@ "roughjs": "4.5.2", "sass": "1.51.0", "socket.io-client": "2.3.1", - "tunnel-rat": "0.1.0", + "tunnel-rat": "0.1.2", "workbox-background-sync": "^6.5.4", "workbox-broadcast-update": "^6.5.4", "workbox-cacheable-response": "^6.5.4", diff --git a/src/appState.ts b/src/appState.ts index 6f4db7557..aaac94879 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -58,7 +58,7 @@ export const getDefaultAppState = (): Omit< fileHandle: null, gridSize: null, isBindingEnabled: true, - isSidebarDocked: false, + defaultSidebarDockedPreference: false, isLoading: false, isResizing: false, isRotating: false, @@ -150,7 +150,11 @@ const APP_STATE_STORAGE_CONF = (< gridSize: { browser: true, export: true, server: true }, height: { browser: false, export: false, server: false }, isBindingEnabled: { browser: false, export: false, server: false }, - isSidebarDocked: { browser: true, export: false, server: false }, + defaultSidebarDockedPreference: { + browser: true, + export: false, + server: false, + }, isLoading: { browser: false, export: false, server: false }, isResizing: { browser: false, export: false, server: false }, isRotating: { browser: false, export: false, server: false }, diff --git a/src/components/App.tsx b/src/components/App.tsx index d22a0507c..a317dd9b6 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -210,6 +210,8 @@ import { PointerDownState, SceneData, Device, + SidebarName, + SidebarTabName, } from "../types"; import { debounce, @@ -299,6 +301,9 @@ import { activeConfirmDialogAtom } from "./ActiveConfirmDialog"; import { actionWrapTextInContainer } from "../actions/actionBoundText"; import BraveMeasureTextError from "./BraveMeasureTextError"; +const AppContext = React.createContext(null!); +const AppPropsContext = React.createContext(null!); + const deviceContextInitialValue = { isSmScreen: false, isMobile: false, @@ -340,6 +345,8 @@ const ExcalidrawActionManagerContext = React.createContext( ); ExcalidrawActionManagerContext.displayName = "ExcalidrawActionManagerContext"; +export const useApp = () => useContext(AppContext); +export const useAppProps = () => useContext(AppPropsContext); export const useDevice = () => useContext(DeviceContext); export const useExcalidrawContainer = () => useContext(ExcalidrawContainerContext); @@ -400,7 +407,7 @@ class App extends React.Component { private nearestScrollableContainer: HTMLElement | Document | undefined; public library: AppClassProperties["library"]; public libraryItemsFromStorage: LibraryItems | undefined; - private id: string; + public id: string; private history: History; private excalidrawContainerValue: { container: HTMLDivElement | null; @@ -438,7 +445,7 @@ class App extends React.Component { width: window.innerWidth, height: window.innerHeight, showHyperlinkPopup: false, - isSidebarDocked: false, + defaultSidebarDockedPreference: false, }; this.id = nanoid(); @@ -469,7 +476,7 @@ class App extends React.Component { setActiveTool: this.setActiveTool, setCursor: this.setCursor, resetCursor: this.resetCursor, - toggleMenu: this.toggleMenu, + toggleSidebar: this.toggleSidebar, } as const; if (typeof excalidrawRef === "function") { excalidrawRef(api); @@ -577,101 +584,91 @@ class App extends React.Component { this.props.handleKeyboardGlobally ? undefined : this.onKeyDown } > - - - - - - - - this.addElementsFromPasteOrLibrary({ - elements, - position: "center", - files: null, - }) - } - langCode={getLanguage().code} - renderTopRightUI={renderTopRightUI} - renderCustomStats={renderCustomStats} - renderCustomSidebar={this.props.renderSidebar} - showExitZenModeBtn={ - typeof this.props?.zenModeEnabled === "undefined" && - this.state.zenModeEnabled - } - libraryReturnUrl={this.props.libraryReturnUrl} - UIOptions={this.props.UIOptions} - focusContainer={this.focusContainer} - library={this.library} - id={this.id} - onImageAction={this.onImageAction} - renderWelcomeScreen={ - !this.state.isLoading && - this.state.showWelcomeScreen && - this.state.activeTool.type === "selection" && - !this.scene.getElementsIncludingDeleted().length - } + + + + + + + - {this.props.children} - -
-
- {selectedElement.length === 1 && - !this.state.contextMenu && - this.state.showHyperlinkPopup && ( - + - )} - {this.state.toast !== null && ( - this.setToast(null)} - duration={this.state.toast.duration} - closable={this.state.toast.closable} - /> - )} - {this.state.contextMenu && ( - - )} -
{this.renderCanvas()}
- - {" "} - - - - + actionManager={this.actionManager} + elements={this.scene.getNonDeletedElements()} + onLockToggle={this.toggleLock} + onPenModeToggle={this.togglePenMode} + onHandToolToggle={this.onHandToolToggle} + langCode={getLanguage().code} + renderTopRightUI={renderTopRightUI} + renderCustomStats={renderCustomStats} + showExitZenModeBtn={ + typeof this.props?.zenModeEnabled === "undefined" && + this.state.zenModeEnabled + } + UIOptions={this.props.UIOptions} + onImageAction={this.onImageAction} + renderWelcomeScreen={ + !this.state.isLoading && + this.state.showWelcomeScreen && + this.state.activeTool.type === "selection" && + !this.scene.getElementsIncludingDeleted().length + } + > + {this.props.children} +
+
+
+ {selectedElement.length === 1 && + !this.state.contextMenu && + this.state.showHyperlinkPopup && ( + + )} + {this.state.toast !== null && ( + this.setToast(null)} + duration={this.state.toast.duration} + closable={this.state.toast.closable} + /> + )} + {this.state.contextMenu && ( + + )} +
{this.renderCanvas()}
+ + {" "} + + + + + +
); } public focusContainer: AppClassProperties["focusContainer"] = () => { - if (this.props.autoFocus) { - this.excalidrawContainerRef.current?.focus(); - } + this.excalidrawContainerRef.current?.focus(); }; public getSceneElementsIncludingDeleted = () => { @@ -682,6 +679,14 @@ class App extends React.Component { return this.scene.getNonDeletedElements(); }; + public onInsertElements = (elements: readonly ExcalidrawElement[]) => { + this.addElementsFromPasteOrLibrary({ + elements, + position: "center", + files: null, + }); + }; + private syncActionResult = withBatchedUpdates( (actionResult: ActionResult) => { if (this.unmounted || actionResult === false) { @@ -951,7 +956,7 @@ class App extends React.Component { this.scene.addCallback(this.onSceneUpdated); this.addEventListeners(); - if (this.excalidrawContainerRef.current) { + if (this.props.autoFocus && this.excalidrawContainerRef.current) { this.focusContainer(); } @@ -1679,7 +1684,7 @@ class App extends React.Component { openSidebar: this.state.openSidebar && this.device.canDeviceFitSidebar && - this.state.isSidebarDocked + this.state.defaultSidebarDockedPreference ? this.state.openSidebar : null, selectedElementIds: newElements.reduce( @@ -2017,30 +2022,24 @@ class App extends React.Component { /** * @returns whether the menu was toggled on or off */ - public toggleMenu = ( - type: "library" | "customSidebar", - force?: boolean, - ): boolean => { - if (type === "customSidebar" && !this.props.renderSidebar) { - console.warn( - `attempting to toggle "customSidebar", but no "props.renderSidebar" is defined`, - ); - return false; + public toggleSidebar = ({ + name, + tab, + force, + }: { + name: SidebarName; + tab?: SidebarTabName; + force?: boolean; + }): boolean => { + let nextName; + if (force === undefined) { + nextName = this.state.openSidebar?.name === name ? null : name; + } else { + nextName = force ? name : null; } + this.setState({ openSidebar: nextName ? { name: nextName, tab } : null }); - if (type === "library" || type === "customSidebar") { - let nextValue; - if (force === undefined) { - nextValue = this.state.openSidebar === type ? null : type; - } else { - nextValue = force ? type : null; - } - this.setState({ openSidebar: nextValue }); - - return !!nextValue; - } - - return false; + return !!nextName; }; private updateCurrentCursorPosition = withBatchedUpdates( diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 3303c3ebf..bf548d72f 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,8 +1,12 @@ +import clsx from "clsx"; +import { composeEventHandlers } from "../utils"; import "./Button.scss"; interface ButtonProps extends React.HTMLAttributes { type?: "button" | "submit" | "reset"; onSelect: () => any; + /** whether button is in active state */ + selected?: boolean; children: React.ReactNode; className?: string; } @@ -15,18 +19,18 @@ interface ButtonProps extends React.HTMLAttributes { export const Button = ({ type = "button", onSelect, + selected, children, className = "", ...rest }: ButtonProps) => { return (
@@ -334,21 +325,21 @@ const LayerUI = ({ }; const renderSidebars = () => { - return appState.openSidebar === "customSidebar" ? ( - renderCustomSidebar?.() || null - ) : appState.openSidebar === "library" ? ( - { + trackEvent( + "sidebar", + `toggleDock (${docked ? "dock" : "undock"})`, + `(${device.isMobile ? "mobile" : "desktop"})`, + ); + }} /> - ) : null; + ); }; - const [hostSidebarCounters] = useAtom(hostSidebarCountersAtom, jotaiScope); + const isSidebarDocked = useAtomValue(isSidebarDockedAtom, jotaiScope); const layerUIJSX = ( <> @@ -358,8 +349,25 @@ const LayerUI = ({ {children} {/* render component fallbacks. Can be rendered anywhere as they'll be tunneled away. We only render tunneled components that actually - have defaults when host do not render anything. */} + have defaults when host do not render anything. */} + { + if (open) { + trackEvent( + "sidebar", + `${DEFAULT_SIDEBAR.name} (open)`, + `button (${device.isMobile ? "mobile" : "desktop"})`, + ); + } + }} + tab={DEFAULT_SIDEBAR.defaultTab} + > + {t("toolBar.library")} + {/* ------------------------------------------------------------------ */} {appState.isLoading && } @@ -382,7 +390,6 @@ const LayerUI = ({ setAppState({ pasteDialog: { shown: false, data: null }, @@ -410,7 +417,6 @@ const LayerUI = ({ renderWelcomeScreen={renderWelcomeScreen} /> )} - {!device.isMobile && ( <>
- {renderWelcomeScreen && } + {renderWelcomeScreen && } {renderFixedSideContainer()} diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/children-components/main-menu.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/main-menu.mdx index 8fbf228df..2494df108 100644 --- a/dev-docs/docs/@excalidraw/excalidraw/api/children-components/main-menu.mdx +++ b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/main-menu.mdx @@ -14,8 +14,7 @@ function App() { Item1 window.alert("Item2")}> - {" "} - Item 2{" "} + Item 2 @@ -93,7 +92,6 @@ function App() { style={{ height: "2rem" }} onClick={() => window.alert("custom menu item")} > - {" "} custom item diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/props/render-props.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/props/render-props.mdx index ca329e3e6..6531e29ec 100644 --- a/dev-docs/docs/@excalidraw/excalidraw/api/props/render-props.mdx +++ b/dev-docs/docs/@excalidraw/excalidraw/api/props/render-props.mdx @@ -3,7 +3,7 @@ ## renderTopRightUI
-  (isMobile: boolean, appState:{" "}
+  (isMobile: boolean, appState:
   
     AppState
   
@@ -29,8 +29,7 @@ function App() {
               }}
               onClick={() => window.alert("This is dummy top right UI")}
             >
-              {" "}
-              Click me{" "}
+              Click me
             
           );
         }}
@@ -55,8 +54,7 @@ function App() {
        (
           

- {" "} - Dummy stats will be shown here{" "} + Dummy stats will be shown here

)} /> @@ -105,8 +103,7 @@ function App() { return (
{ )}
{this.renderCanvas()}
- {" "} + diff --git a/src/excalidraw-app/collab/RoomDialog.tsx b/src/excalidraw-app/collab/RoomDialog.tsx index 50f586efc..42c123302 100644 --- a/src/excalidraw-app/collab/RoomDialog.tsx +++ b/src/excalidraw-app/collab/RoomDialog.tsx @@ -154,7 +154,7 @@ const RoomDialog = ({

{" "} + {t("roomDialog.desc_privacy")}

{t("roomDialog.desc_exitSession")}

diff --git a/src/packages/excalidraw/example/App.tsx b/src/packages/excalidraw/example/App.tsx index 85993a683..3a0634e63 100644 --- a/src/packages/excalidraw/example/App.tsx +++ b/src/packages/excalidraw/example/App.tsx @@ -161,8 +161,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) { onClick={() => alert("This is an empty top right UI")} style={{ height: "2.5rem" }} > - {" "} - Click me{" "} + Click me ); diff --git a/src/packages/excalidraw/example/CustomFooter.tsx b/src/packages/excalidraw/example/CustomFooter.tsx index fbc2ea732..5c47de6c6 100644 --- a/src/packages/excalidraw/example/CustomFooter.tsx +++ b/src/packages/excalidraw/example/CustomFooter.tsx @@ -65,8 +65,7 @@ const CustomFooter = ({ className="custom-footer" onClick={() => alert("This is dummy footer")} > - {" "} - custom footer{" "} + custom footer ); diff --git a/src/packages/excalidraw/example/sidebar/ExampleSidebar.tsx b/src/packages/excalidraw/example/sidebar/ExampleSidebar.tsx index 793d17b05..4c51ecdc2 100644 --- a/src/packages/excalidraw/example/sidebar/ExampleSidebar.tsx +++ b/src/packages/excalidraw/example/sidebar/ExampleSidebar.tsx @@ -11,7 +11,7 @@ export default function Sidebar({ children }: { children: React.ReactNode }) {
- {" "} +
diff --git a/src/tests/packages/__snapshots__/excalidraw.test.tsx.snap b/src/tests/packages/__snapshots__/excalidraw.test.tsx.snap index 09402981e..d703dff87 100644 --- a/src/tests/packages/__snapshots__/excalidraw.test.tsx.snap +++ b/src/tests/packages/__snapshots__/excalidraw.test.tsx.snap @@ -43,7 +43,6 @@ exports[` should render main menu with host menu items
diff --git a/src/tests/packages/excalidraw.test.tsx b/src/tests/packages/excalidraw.test.tsx index a0d495936..a5734b2ed 100644 --- a/src/tests/packages/excalidraw.test.tsx +++ b/src/tests/packages/excalidraw.test.tsx @@ -220,7 +220,6 @@ describe("", () => { style={{ height: "2rem" }} onClick={() => window.alert("custom menu item")} > - {" "} custom item @@ -345,7 +344,6 @@ describe("", () => { style={{ height: "2rem" }} onClick={() => window.alert("custom menu item")} > - {" "} custom menu item From 5b7596582f44f951147886152966672ba876660c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Moln=C3=A1r?= <38168628+barnabasmolnar@users.noreply.github.com> Date: Thu, 18 May 2023 16:06:27 +0200 Subject: [PATCH 073/451] feat: color picker redesign (#6216) Co-authored-by: Maielo Co-authored-by: dwelle Co-authored-by: Aakansha Doshi --- .npmrc | 1 + package.json | 1 + src/actions/actionCanvas.tsx | 32 +- src/actions/actionFlip.ts | 6 +- src/actions/actionProperties.tsx | 26 +- src/actions/actionStyles.test.tsx | 30 +- src/appState.ts | 4 +- src/charts.ts | 32 +- src/clients.ts | 20 +- src/colors.ts | 183 +- src/components/App.tsx | 6 +- src/components/ColorPicker.tsx | 430 --- src/components/ColorPicker/ColorInput.tsx | 75 + .../{ => ColorPicker}/ColorPicker.scss | 161 +- src/components/ColorPicker/ColorPicker.tsx | 235 ++ .../ColorPicker/CustomColorList.tsx | 63 + src/components/ColorPicker/HotkeyLabel.tsx | 29 + src/components/ColorPicker/Picker.tsx | 156 + .../ColorPicker/PickerColorList.tsx | 86 + src/components/ColorPicker/PickerHeading.tsx | 7 + src/components/ColorPicker/ShadeList.tsx | 105 + src/components/ColorPicker/TopPicks.tsx | 64 + .../ColorPicker/colorPickerUtils.ts | 139 + .../ColorPicker/keyboardNavHandlers.ts | 249 ++ src/components/LibraryUnit.tsx | 4 +- src/components/ProjectName.tsx | 3 +- .../dropdownMenu/DropdownMenuContent.tsx | 2 +- src/constants.ts | 6 +- src/data/restore.ts | 6 +- src/element/textWysiwyg.test.tsx | 2 +- src/element/textWysiwyg.tsx | 54 +- src/excalidraw-app/collab/RoomDialog.tsx | 5 +- src/i18n.ts | 14 +- src/locales/en.json | 65 +- src/packages/excalidraw/example/App.tsx | 7 +- src/packages/excalidraw/package.json | 2 +- src/packages/excalidraw/yarn.lock | 8 +- src/tests/MobileMenu.test.tsx | 1 + .../__snapshots__/contextmenu.test.tsx.snap | 262 +- .../__snapshots__/dragCreate.test.tsx.snap | 10 +- .../linearElementEditor.test.tsx.snap | 2 +- src/tests/__snapshots__/move.test.tsx.snap | 12 +- .../multiPointCreate.test.tsx.snap | 4 +- .../regressionTests.test.tsx.snap | 977 +++--- .../__snapshots__/selection.test.tsx.snap | 10 +- src/tests/contextmenu.test.tsx | 21 +- .../data/__snapshots__/restore.test.ts.snap | 12 +- src/tests/helpers/ui.ts | 9 + .../__snapshots__/excalidraw.test.tsx.snap | 102 +- .../packages/__snapshots__/utils.test.ts.snap | 2 +- src/tests/regressionTests.test.tsx | 27 +- src/tests/test-utils.ts | 27 +- src/types.ts | 7 +- src/utils.ts | 5 +- yarn.lock | 2901 +++++++++-------- 55 files changed, 4010 insertions(+), 2699 deletions(-) delete mode 100644 src/components/ColorPicker.tsx create mode 100644 src/components/ColorPicker/ColorInput.tsx rename src/components/{ => ColorPicker}/ColorPicker.scss (63%) create mode 100644 src/components/ColorPicker/ColorPicker.tsx create mode 100644 src/components/ColorPicker/CustomColorList.tsx create mode 100644 src/components/ColorPicker/HotkeyLabel.tsx create mode 100644 src/components/ColorPicker/Picker.tsx create mode 100644 src/components/ColorPicker/PickerColorList.tsx create mode 100644 src/components/ColorPicker/PickerHeading.tsx create mode 100644 src/components/ColorPicker/ShadeList.tsx create mode 100644 src/components/ColorPicker/TopPicks.tsx create mode 100644 src/components/ColorPicker/colorPickerUtils.ts create mode 100644 src/components/ColorPicker/keyboardNavHandlers.ts diff --git a/.npmrc b/.npmrc index cffe8cdef..1b78f1c6f 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ save-exact=true +legacy-peer-deps=true diff --git a/package.json b/package.json index 57bdfe562..4556cb5f7 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ ] }, "dependencies": { + "@radix-ui/react-popover": "1.0.3", "@radix-ui/react-tabs": "1.0.2", "@sentry/browser": "6.2.5", "@sentry/integrations": "6.2.5", diff --git a/src/actions/actionCanvas.tsx b/src/actions/actionCanvas.tsx index 440c59191..16c4fad19 100644 --- a/src/actions/actionCanvas.tsx +++ b/src/actions/actionCanvas.tsx @@ -1,4 +1,4 @@ -import { ColorPicker } from "../components/ColorPicker"; +import { ColorPicker } from "../components/ColorPicker/ColorPicker"; import { ZoomInIcon, ZoomOutIcon } from "../components/icons"; import { ToolButton } from "../components/ToolButton"; import { CURSOR_TYPE, MIN_ZOOM, THEME, ZOOM_STEP } from "../constants"; @@ -19,6 +19,7 @@ import { isEraserActive, isHandToolActive, } from "../appState"; +import { DEFAULT_CANVAS_BACKGROUND_PICKS } from "../colors"; export const actionChangeViewBackgroundColor = register({ name: "changeViewBackgroundColor", @@ -35,24 +36,21 @@ export const actionChangeViewBackgroundColor = register({ commitToHistory: !!value.viewBackgroundColor, }; }, - PanelComponent: ({ elements, appState, updateData }) => { + PanelComponent: ({ elements, appState, updateData, appProps }) => { // FIXME move me to src/components/mainMenu/DefaultItems.tsx return ( -
- updateData({ viewBackgroundColor: color })} - isActive={appState.openPopup === "canvasColorPicker"} - setActive={(active) => - updateData({ openPopup: active ? "canvasColorPicker" : null }) - } - data-testid="canvas-background-picker" - elements={elements} - appState={appState} - /> -
+ updateData({ viewBackgroundColor: color })} + data-testid="canvas-background-picker" + elements={elements} + appState={appState} + updateData={updateData} + /> ); }, }); diff --git a/src/actions/actionFlip.ts b/src/actions/actionFlip.ts index ff6bfe4b7..0dadc23b1 100644 --- a/src/actions/actionFlip.ts +++ b/src/actions/actionFlip.ts @@ -14,7 +14,7 @@ import { } from "../element/bounds"; import { isLinearElement } from "../element/typeChecks"; import { LinearElementEditor } from "../element/linearElementEditor"; -import { KEYS } from "../keys"; +import { CODES, KEYS } from "../keys"; const enableActionFlipHorizontal = ( elements: readonly ExcalidrawElement[], @@ -48,7 +48,7 @@ export const actionFlipHorizontal = register({ commitToHistory: true, }; }, - keyTest: (event) => event.shiftKey && event.code === "KeyH", + keyTest: (event) => event.shiftKey && event.code === CODES.H, contextItemLabel: "labels.flipHorizontal", predicate: (elements, appState) => enableActionFlipHorizontal(elements, appState), @@ -65,7 +65,7 @@ export const actionFlipVertical = register({ }; }, keyTest: (event) => - event.shiftKey && event.code === "KeyV" && !event[KEYS.CTRL_OR_CMD], + event.shiftKey && event.code === CODES.V && !event[KEYS.CTRL_OR_CMD], contextItemLabel: "labels.flipVertical", predicate: (elements, appState) => enableActionFlipVertical(elements, appState), diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index 382e964b9..6e921d6ea 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -1,7 +1,13 @@ import { AppState } from "../../src/types"; +import { + DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE, + DEFAULT_ELEMENT_BACKGROUND_PICKS, + DEFAULT_ELEMENT_STROKE_COLOR_PALETTE, + DEFAULT_ELEMENT_STROKE_PICKS, +} from "../colors"; import { trackEvent } from "../analytics"; import { ButtonIconSelect } from "../components/ButtonIconSelect"; -import { ColorPicker } from "../components/ColorPicker"; +import { ColorPicker } from "../components/ColorPicker/ColorPicker"; import { IconPicker } from "../components/IconPicker"; // TODO barnabasmolnar/editor-redesign // TextAlignTopIcon, TextAlignBottomIcon,TextAlignMiddleIcon, @@ -226,10 +232,12 @@ export const actionChangeStrokeColor = register({ commitToHistory: !!value.currentItemStrokeColor, }; }, - PanelComponent: ({ elements, appState, updateData }) => ( + PanelComponent: ({ elements, appState, updateData, appProps }) => ( <> updateData({ currentItemStrokeColor: color })} - isActive={appState.openPopup === "strokeColorPicker"} - setActive={(active) => - updateData({ openPopup: active ? "strokeColorPicker" : null }) - } elements={elements} appState={appState} + updateData={updateData} /> ), @@ -269,10 +274,12 @@ export const actionChangeBackgroundColor = register({ commitToHistory: !!value.currentItemBackgroundColor, }; }, - PanelComponent: ({ elements, appState, updateData }) => ( + PanelComponent: ({ elements, appState, updateData, appProps }) => ( <> updateData({ currentItemBackgroundColor: color })} - isActive={appState.openPopup === "backgroundColorPicker"} - setActive={(active) => - updateData({ openPopup: active ? "backgroundColorPicker" : null }) - } elements={elements} appState={appState} + updateData={updateData} /> ), diff --git a/src/actions/actionStyles.test.tsx b/src/actions/actionStyles.test.tsx index c73864cc4..238196dfc 100644 --- a/src/actions/actionStyles.test.tsx +++ b/src/actions/actionStyles.test.tsx @@ -1,9 +1,14 @@ import ExcalidrawApp from "../excalidraw-app"; -import { t } from "../i18n"; import { CODES } from "../keys"; import { API } from "../tests/helpers/api"; import { Keyboard, Pointer, UI } from "../tests/helpers/ui"; -import { fireEvent, render, screen } from "../tests/test-utils"; +import { + act, + fireEvent, + render, + screen, + togglePopover, +} from "../tests/test-utils"; import { copiedStyles } from "./actionStyles"; const { h } = window; @@ -14,7 +19,14 @@ describe("actionStyles", () => { beforeEach(async () => { await render(); }); - it("should copy & paste styles via keyboard", () => { + + afterEach(async () => { + // https://github.com/floating-ui/floating-ui/issues/1908#issuecomment-1301553793 + // affects node v16+ + await act(async () => {}); + }); + + it("should copy & paste styles via keyboard", async () => { UI.clickTool("rectangle"); mouse.down(10, 10); mouse.up(20, 20); @@ -24,10 +36,10 @@ describe("actionStyles", () => { mouse.up(20, 20); // Change some styles of second rectangle - UI.clickLabeledElement("Stroke"); - UI.clickLabeledElement(t("colors.c92a2a")); - UI.clickLabeledElement("Background"); - UI.clickLabeledElement(t("colors.e64980")); + togglePopover("Stroke"); + UI.clickOnTestId("color-red"); + togglePopover("Background"); + UI.clickOnTestId("color-blue"); // Fill style fireEvent.click(screen.getByTitle("Cross-hatch")); // Stroke width @@ -60,8 +72,8 @@ describe("actionStyles", () => { const firstRect = API.getSelectedElement(); expect(firstRect.id).toBe(h.elements[0].id); - expect(firstRect.strokeColor).toBe("#c92a2a"); - expect(firstRect.backgroundColor).toBe("#e64980"); + expect(firstRect.strokeColor).toBe("#e03131"); + expect(firstRect.backgroundColor).toBe("#a5d8ff"); expect(firstRect.fillStyle).toBe("cross-hatch"); expect(firstRect.strokeWidth).toBe(2); // Bold: 2 expect(firstRect.strokeStyle).toBe("dotted"); diff --git a/src/appState.ts b/src/appState.ts index aaac94879..4468eb966 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -1,4 +1,4 @@ -import oc from "open-color"; +import { COLOR_PALETTE } from "./colors"; import { DEFAULT_ELEMENT_PROPS, DEFAULT_FONT_FAMILY, @@ -84,7 +84,7 @@ export const getDefaultAppState = (): Omit< startBoundElement: null, suggestedBindings: [], toast: null, - viewBackgroundColor: oc.white, + viewBackgroundColor: COLOR_PALETTE.white, zenModeEnabled: false, zoom: { value: 1 as NormalizedZoomValue, diff --git a/src/charts.ts b/src/charts.ts index c3b0950d1..b5714686c 100644 --- a/src/charts.ts +++ b/src/charts.ts @@ -1,5 +1,14 @@ -import colors from "./colors"; -import { DEFAULT_FONT_SIZE, ENV } from "./constants"; +import { + COLOR_PALETTE, + DEFAULT_CHART_COLOR_INDEX, + getAllColorsSpecificShade, +} from "./colors"; +import { + DEFAULT_FONT_FAMILY, + DEFAULT_FONT_SIZE, + ENV, + VERTICAL_ALIGN, +} from "./constants"; import { newElement, newLinearElement, newTextElement } from "./element"; import { NonDeletedExcalidrawElement } from "./element/types"; import { randomId } from "./random"; @@ -153,15 +162,22 @@ export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => { return result; }; -const bgColors = colors.elementBackground.slice( - 2, - colors.elementBackground.length, -); +const bgColors = getAllColorsSpecificShade(DEFAULT_CHART_COLOR_INDEX); // Put all the common properties here so when the whole chart is selected // the properties dialog shows the correct selected values const commonProps = { - strokeColor: colors.elementStroke[0], + fillStyle: "hachure", + fontFamily: DEFAULT_FONT_FAMILY, + fontSize: DEFAULT_FONT_SIZE, + opacity: 100, + roughness: 1, + strokeColor: COLOR_PALETTE.black, + roundness: null, + strokeStyle: "solid", + strokeWidth: 1, + verticalAlign: VERTICAL_ALIGN.MIDDLE, + locked: false, } as const; const getChartDimentions = (spreadsheet: Spreadsheet) => { @@ -322,7 +338,7 @@ const chartBaseElements = ( y: y - chartHeight, width: chartWidth, height: chartHeight, - strokeColor: colors.elementStroke[0], + strokeColor: COLOR_PALETTE.black, fillStyle: "solid", opacity: 6, }) diff --git a/src/clients.ts b/src/clients.ts index 94ffd7a62..604936e33 100644 --- a/src/clients.ts +++ b/src/clients.ts @@ -1,6 +1,17 @@ -import colors from "./colors"; +import { + DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX, + DEFAULT_ELEMENT_STROKE_COLOR_INDEX, + getAllColorsSpecificShade, +} from "./colors"; import { AppState } from "./types"; +const BG_COLORS = getAllColorsSpecificShade( + DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX, +); +const STROKE_COLORS = getAllColorsSpecificShade( + DEFAULT_ELEMENT_STROKE_COLOR_INDEX, +); + export const getClientColors = (clientId: string, appState: AppState) => { if (appState?.collaborators) { const currentUser = appState.collaborators.get(clientId); @@ -11,12 +22,9 @@ export const getClientColors = (clientId: string, appState: AppState) => { // Naive way of getting an integer out of the clientId const sum = clientId.split("").reduce((a, str) => a + str.charCodeAt(0), 0); - // Skip transparent & gray colors - const backgrounds = colors.elementBackground.slice(3); - const strokes = colors.elementStroke.slice(3); return { - background: backgrounds[sum % backgrounds.length], - stroke: strokes[sum % strokes.length], + background: BG_COLORS[sum % BG_COLORS.length], + stroke: STROKE_COLORS[sum % STROKE_COLORS.length], }; }; diff --git a/src/colors.ts b/src/colors.ts index 63cd72839..198ec12e2 100644 --- a/src/colors.ts +++ b/src/colors.ts @@ -1,22 +1,167 @@ import oc from "open-color"; +import { Merge } from "./utility-types"; -const shades = (index: number) => [ - oc.red[index], - oc.pink[index], - oc.grape[index], - oc.violet[index], - oc.indigo[index], - oc.blue[index], - oc.cyan[index], - oc.teal[index], - oc.green[index], - oc.lime[index], - oc.yellow[index], - oc.orange[index], -]; - -export default { - canvasBackground: [oc.white, oc.gray[0], oc.gray[1], ...shades(0)], - elementBackground: ["transparent", oc.gray[4], oc.gray[6], ...shades(6)], - elementStroke: [oc.black, oc.gray[8], oc.gray[7], ...shades(9)], +// FIXME can't put to utils.ts rn because of circular dependency +const pick = , K extends readonly (keyof R)[]>( + source: R, + keys: K, +) => { + return keys.reduce((acc, key: K[number]) => { + if (key in source) { + acc[key] = source[key]; + } + return acc; + }, {} as Pick) as Pick; }; + +export type ColorPickerColor = + | Exclude + | "transparent" + | "bronze"; +export type ColorTuple = readonly [string, string, string, string, string]; +export type ColorPalette = Merge< + Record, + { black: string; white: string; transparent: string } +>; + +// used general type instead of specific type (ColorPalette) to support custom colors +export type ColorPaletteCustom = { [key: string]: ColorTuple | string }; +export type ColorShadesIndexes = [number, number, number, number, number]; + +export const MAX_CUSTOM_COLORS_USED_IN_CANVAS = 5; +export const COLORS_PER_ROW = 5; + +export const DEFAULT_CHART_COLOR_INDEX = 4; + +export const DEFAULT_ELEMENT_STROKE_COLOR_INDEX = 4; +export const DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX = 1; +export const ELEMENTS_PALETTE_SHADE_INDEXES = [0, 2, 4, 6, 8] as const; +export const CANVAS_PALETTE_SHADE_INDEXES = [0, 1, 2, 3, 4] as const; + +export const getSpecificColorShades = ( + color: Exclude< + ColorPickerColor, + "transparent" | "white" | "black" | "bronze" + >, + indexArr: Readonly, +) => { + return indexArr.map((index) => oc[color][index]) as any as ColorTuple; +}; + +export const COLOR_PALETTE = { + transparent: "transparent", + black: "#1e1e1e", + white: "#ffffff", + // open-colors + gray: getSpecificColorShades("gray", ELEMENTS_PALETTE_SHADE_INDEXES), + red: getSpecificColorShades("red", ELEMENTS_PALETTE_SHADE_INDEXES), + pink: getSpecificColorShades("pink", ELEMENTS_PALETTE_SHADE_INDEXES), + grape: getSpecificColorShades("grape", ELEMENTS_PALETTE_SHADE_INDEXES), + violet: getSpecificColorShades("violet", ELEMENTS_PALETTE_SHADE_INDEXES), + blue: getSpecificColorShades("blue", ELEMENTS_PALETTE_SHADE_INDEXES), + cyan: getSpecificColorShades("cyan", ELEMENTS_PALETTE_SHADE_INDEXES), + teal: getSpecificColorShades("teal", ELEMENTS_PALETTE_SHADE_INDEXES), + green: getSpecificColorShades("green", ELEMENTS_PALETTE_SHADE_INDEXES), + yellow: getSpecificColorShades("yellow", ELEMENTS_PALETTE_SHADE_INDEXES), + orange: getSpecificColorShades("orange", ELEMENTS_PALETTE_SHADE_INDEXES), + // radix bronze shades 3,5,7,9,11 + bronze: ["#f8f1ee", "#eaddd7", "#d2bab0", "#a18072", "#846358"], +} as ColorPalette; + +const COMMON_ELEMENT_SHADES = pick(COLOR_PALETTE, [ + "cyan", + "blue", + "violet", + "grape", + "pink", + "green", + "teal", + "yellow", + "orange", + "red", +]); + +// ----------------------------------------------------------------------------- +// quick picks defaults +// ----------------------------------------------------------------------------- + +// ORDER matters for positioning in quick picker +export const DEFAULT_ELEMENT_STROKE_PICKS = [ + COLOR_PALETTE.black, + COLOR_PALETTE.red[DEFAULT_ELEMENT_STROKE_COLOR_INDEX], + COLOR_PALETTE.green[DEFAULT_ELEMENT_STROKE_COLOR_INDEX], + COLOR_PALETTE.blue[DEFAULT_ELEMENT_STROKE_COLOR_INDEX], + COLOR_PALETTE.yellow[DEFAULT_ELEMENT_STROKE_COLOR_INDEX], +] as ColorTuple; + +// ORDER matters for positioning in quick picker +export const DEFAULT_ELEMENT_BACKGROUND_PICKS = [ + COLOR_PALETTE.transparent, + COLOR_PALETTE.red[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX], + COLOR_PALETTE.green[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX], + COLOR_PALETTE.blue[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX], + COLOR_PALETTE.yellow[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX], +] as ColorTuple; + +// ORDER matters for positioning in quick picker +export const DEFAULT_CANVAS_BACKGROUND_PICKS = [ + COLOR_PALETTE.white, + // radix slate2 + "#f8f9fa", + // radix blue2 + "#f5faff", + // radix yellow2 + "#fffce8", + // radix bronze2 + "#fdf8f6", +] as ColorTuple; + +// ----------------------------------------------------------------------------- +// palette defaults +// ----------------------------------------------------------------------------- + +export const DEFAULT_ELEMENT_STROKE_COLOR_PALETTE = { + // 1st row + transparent: COLOR_PALETTE.transparent, + white: COLOR_PALETTE.white, + gray: COLOR_PALETTE.gray, + black: COLOR_PALETTE.black, + bronze: COLOR_PALETTE.bronze, + // rest + ...COMMON_ELEMENT_SHADES, +} as const; + +// ORDER matters for positioning in pallete (5x3 grid)s +export const DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE = { + transparent: COLOR_PALETTE.transparent, + white: COLOR_PALETTE.white, + gray: COLOR_PALETTE.gray, + black: COLOR_PALETTE.black, + bronze: COLOR_PALETTE.bronze, + + ...COMMON_ELEMENT_SHADES, +} as const; + +// ----------------------------------------------------------------------------- +// helpers +// ----------------------------------------------------------------------------- + +// !!!MUST BE WITHOUT GRAY, TRANSPARENT AND BLACK!!! +export const getAllColorsSpecificShade = (index: 0 | 1 | 2 | 3 | 4) => + [ + // 2nd row + COLOR_PALETTE.cyan[index], + COLOR_PALETTE.blue[index], + COLOR_PALETTE.violet[index], + COLOR_PALETTE.grape[index], + COLOR_PALETTE.pink[index], + + // 3rd row + COLOR_PALETTE.green[index], + COLOR_PALETTE.teal[index], + COLOR_PALETTE.yellow[index], + COLOR_PALETTE.orange[index], + COLOR_PALETTE.red[index], + ] as const; + +// ----------------------------------------------------------------------------- diff --git a/src/components/App.tsx b/src/components/App.tsx index 752854e92..e6f961698 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -313,6 +313,7 @@ const deviceContextInitialValue = { isMobile: false, isTouchScreen: false, canDeviceFitSidebar: false, + isLandscape: false, }; const DeviceContext = React.createContext(deviceContextInitialValue); DeviceContext.displayName = "DeviceContext"; @@ -947,6 +948,7 @@ class App extends React.Component { ? this.props.UIOptions.dockedSidebarBreakpoint : MQ_RIGHT_SIDEBAR_MIN_WIDTH; this.device = updateObject(this.device, { + isLandscape: width > height, isSmScreen: width < MQ_SM_MAX_WIDTH, isMobile: width < MQ_MAX_WIDTH_PORTRAIT || @@ -2323,11 +2325,11 @@ class App extends React.Component { (hasBackground(this.state.activeTool.type) || selectedElements.some((element) => hasBackground(element.type))) ) { - this.setState({ openPopup: "backgroundColorPicker" }); + this.setState({ openPopup: "elementBackground" }); event.stopPropagation(); } if (event.key === KEYS.S) { - this.setState({ openPopup: "strokeColorPicker" }); + this.setState({ openPopup: "elementStroke" }); event.stopPropagation(); } } diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx deleted file mode 100644 index cb05cf446..000000000 --- a/src/components/ColorPicker.tsx +++ /dev/null @@ -1,430 +0,0 @@ -import React from "react"; -import { Popover } from "./Popover"; -import { isTransparent } from "../utils"; - -import "./ColorPicker.scss"; -import { isArrowKey, KEYS } from "../keys"; -import { t, getLanguage } from "../i18n"; -import { isWritableElement } from "../utils"; -import colors from "../colors"; -import { ExcalidrawElement } from "../element/types"; -import { AppState } from "../types"; - -const MAX_CUSTOM_COLORS = 5; -const MAX_DEFAULT_COLORS = 15; - -export const getCustomColors = ( - elements: readonly ExcalidrawElement[], - type: "elementBackground" | "elementStroke", -) => { - const customColors: string[] = []; - const updatedElements = elements - .filter((element) => !element.isDeleted) - .sort((ele1, ele2) => ele2.updated - ele1.updated); - - let index = 0; - const elementColorTypeMap = { - elementBackground: "backgroundColor", - elementStroke: "strokeColor", - }; - const colorType = elementColorTypeMap[type] as - | "backgroundColor" - | "strokeColor"; - while ( - index < updatedElements.length && - customColors.length < MAX_CUSTOM_COLORS - ) { - const element = updatedElements[index]; - - if ( - customColors.length < MAX_CUSTOM_COLORS && - isCustomColor(element[colorType], type) && - !customColors.includes(element[colorType]) - ) { - customColors.push(element[colorType]); - } - index++; - } - return customColors; -}; - -const isCustomColor = ( - color: string, - type: "elementBackground" | "elementStroke", -) => { - return !colors[type].includes(color); -}; - -const isValidColor = (color: string) => { - const style = new Option().style; - style.color = color; - return !!style.color; -}; - -const getColor = (color: string): string | null => { - if (isTransparent(color)) { - return color; - } - - // testing for `#` first fixes a bug on Electron (more specfically, an - // Obsidian popout window), where a hex color without `#` is (incorrectly) - // considered valid - return isValidColor(`#${color}`) - ? `#${color}` - : isValidColor(color) - ? color - : null; -}; - -// This is a narrow reimplementation of the awesome react-color Twitter component -// https://github.com/casesandberg/react-color/blob/master/src/components/twitter/Twitter.js - -// Unfortunately, we can't detect keyboard layout in the browser. So this will -// only work well for QWERTY but not AZERTY or others... -const keyBindings = [ - ["1", "2", "3", "4", "5"], - ["q", "w", "e", "r", "t"], - ["a", "s", "d", "f", "g"], - ["z", "x", "c", "v", "b"], -].flat(); - -const Picker = ({ - colors, - color, - onChange, - onClose, - label, - showInput = true, - type, - elements, -}: { - colors: string[]; - color: string | null; - onChange: (color: string) => void; - onClose: () => void; - label: string; - showInput: boolean; - type: "canvasBackground" | "elementBackground" | "elementStroke"; - elements: readonly ExcalidrawElement[]; -}) => { - const firstItem = React.useRef(); - const activeItem = React.useRef(); - const gallery = React.useRef(); - const colorInput = React.useRef(); - - const [customColors] = React.useState(() => { - if (type === "canvasBackground") { - return []; - } - return getCustomColors(elements, type); - }); - - React.useEffect(() => { - // After the component is first mounted focus on first input - if (activeItem.current) { - activeItem.current.focus(); - } else if (colorInput.current) { - colorInput.current.focus(); - } else if (gallery.current) { - gallery.current.focus(); - } - }, []); - - const handleKeyDown = (event: React.KeyboardEvent) => { - let handled = false; - if (isArrowKey(event.key)) { - handled = true; - const { activeElement } = document; - const isRTL = getLanguage().rtl; - let isCustom = false; - let index = Array.prototype.indexOf.call( - gallery.current!.querySelector(".color-picker-content--default") - ?.children, - activeElement, - ); - if (index === -1) { - index = Array.prototype.indexOf.call( - gallery.current!.querySelector(".color-picker-content--canvas-colors") - ?.children, - activeElement, - ); - if (index !== -1) { - isCustom = true; - } - } - const parentElement = isCustom - ? gallery.current?.querySelector(".color-picker-content--canvas-colors") - : gallery.current?.querySelector(".color-picker-content--default"); - - if (parentElement && index !== -1) { - const length = parentElement.children.length - (showInput ? 1 : 0); - const nextIndex = - event.key === (isRTL ? KEYS.ARROW_LEFT : KEYS.ARROW_RIGHT) - ? (index + 1) % length - : event.key === (isRTL ? KEYS.ARROW_RIGHT : KEYS.ARROW_LEFT) - ? (length + index - 1) % length - : !isCustom && event.key === KEYS.ARROW_DOWN - ? (index + 5) % length - : !isCustom && event.key === KEYS.ARROW_UP - ? (length + index - 5) % length - : index; - (parentElement.children[nextIndex] as HTMLElement | undefined)?.focus(); - } - event.preventDefault(); - } else if ( - keyBindings.includes(event.key.toLowerCase()) && - !event[KEYS.CTRL_OR_CMD] && - !event.altKey && - !isWritableElement(event.target) - ) { - handled = true; - const index = keyBindings.indexOf(event.key.toLowerCase()); - const isCustom = index >= MAX_DEFAULT_COLORS; - const parentElement = isCustom - ? gallery?.current?.querySelector( - ".color-picker-content--canvas-colors", - ) - : gallery?.current?.querySelector(".color-picker-content--default"); - const actualIndex = isCustom ? index - MAX_DEFAULT_COLORS : index; - ( - parentElement?.children[actualIndex] as HTMLElement | undefined - )?.focus(); - - event.preventDefault(); - } else if (event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) { - handled = true; - event.preventDefault(); - onClose(); - } - if (handled) { - event.nativeEvent.stopImmediatePropagation(); - event.stopPropagation(); - } - }; - - const renderColors = (colors: Array, custom: boolean = false) => { - return colors.map((_color, i) => { - const _colorWithoutHash = _color.replace("#", ""); - const keyBinding = custom - ? keyBindings[i + MAX_DEFAULT_COLORS] - : keyBindings[i]; - const label = custom - ? _colorWithoutHash - : t(`colors.${_colorWithoutHash}`); - return ( - - ); - }); - }; - - return ( -
-
-
-
{ - if (el) { - gallery.current = el; - } - }} - // to allow focusing by clicking but not by tabbing - tabIndex={-1} - > -
- {renderColors(colors)} -
- {!!customColors.length && ( -
- - {t("labels.canvasColors")} - -
- {renderColors(customColors, true)} -
-
- )} - - {showInput && ( - { - onChange(color); - }} - ref={colorInput} - /> - )} -
-
- ); -}; - -const ColorInput = React.forwardRef( - ( - { - color, - onChange, - label, - }: { - color: string | null; - onChange: (color: string) => void; - label: string; - }, - ref, - ) => { - const [innerValue, setInnerValue] = React.useState(color); - const inputRef = React.useRef(null); - - React.useEffect(() => { - setInnerValue(color); - }, [color]); - - React.useImperativeHandle(ref, () => inputRef.current); - - const changeColor = React.useCallback( - (inputValue: string) => { - const value = inputValue.toLowerCase(); - const color = getColor(value); - if (color) { - onChange(color); - } - setInnerValue(value); - }, - [onChange], - ); - - return ( - - ); - }, -); - -ColorInput.displayName = "ColorInput"; - -export const ColorPicker = ({ - type, - color, - onChange, - label, - isActive, - setActive, - elements, - appState, -}: { - type: "canvasBackground" | "elementBackground" | "elementStroke"; - color: string | null; - onChange: (color: string) => void; - label: string; - isActive: boolean; - setActive: (active: boolean) => void; - elements: readonly ExcalidrawElement[]; - appState: AppState; -}) => { - const pickerButton = React.useRef(null); - const coords = pickerButton.current?.getBoundingClientRect(); - - return ( -
-
-
-
- { - onChange(color); - }} - /> -
- - {isActive ? ( -
- - event.target !== pickerButton.current && setActive(false) - } - > - { - onChange(changedColor); - }} - onClose={() => { - setActive(false); - pickerButton.current?.focus(); - }} - label={label} - showInput={false} - type={type} - elements={elements} - /> - -
- ) : null} -
-
- ); -}; diff --git a/src/components/ColorPicker/ColorInput.tsx b/src/components/ColorPicker/ColorInput.tsx new file mode 100644 index 000000000..bb9a85510 --- /dev/null +++ b/src/components/ColorPicker/ColorInput.tsx @@ -0,0 +1,75 @@ +import { useCallback, useEffect, useRef, useState } from "react"; +import { getColor } from "./ColorPicker"; +import { useAtom } from "jotai"; +import { activeColorPickerSectionAtom } from "./colorPickerUtils"; +import { KEYS } from "../../keys"; + +interface ColorInputProps { + color: string | null; + onChange: (color: string) => void; + label: string; +} + +export const ColorInput = ({ color, onChange, label }: ColorInputProps) => { + const [innerValue, setInnerValue] = useState(color); + const [activeSection, setActiveColorPickerSection] = useAtom( + activeColorPickerSectionAtom, + ); + + useEffect(() => { + setInnerValue(color); + }, [color]); + + const changeColor = useCallback( + (inputValue: string) => { + const value = inputValue.toLowerCase(); + const color = getColor(value); + + if (color) { + onChange(color); + } + setInnerValue(value); + }, + [onChange], + ); + + const inputRef = useRef(null); + const divRef = useRef(null); + + useEffect(() => { + if (inputRef.current) { + inputRef.current.focus(); + } + }, [activeSection]); + + return ( + + ); +}; diff --git a/src/components/ColorPicker.scss b/src/components/ColorPicker/ColorPicker.scss similarity index 63% rename from src/components/ColorPicker.scss rename to src/components/ColorPicker/ColorPicker.scss index b816b2553..bc7146b6b 100644 --- a/src/components/ColorPicker.scss +++ b/src/components/ColorPicker/ColorPicker.scss @@ -1,6 +1,134 @@ -@import "../css/variables.module"; +@import "../../css/variables.module"; .excalidraw { + .focus-visible-none { + &:focus-visible { + outline: none !important; + } + } + + .color-picker__heading { + padding: 0 0.5rem; + font-size: 0.75rem; + text-align: left; + } + + .color-picker-container { + display: grid; + grid-template-columns: 1fr 20px 1.625rem; + padding: 0.25rem 0px; + align-items: center; + + @include isMobile { + max-width: 175px; + } + } + + .color-picker__top-picks { + display: flex; + justify-content: space-between; + } + + .color-picker__button { + --radius: 0.25rem; + + padding: 0; + margin: 0; + width: 1.35rem; + height: 1.35rem; + border: 1px solid var(--color-gray-30); + border-radius: var(--radius); + filter: var(--theme-filter); + background-color: var(--swatch-color); + background-position: left center; + position: relative; + font-family: inherit; + box-sizing: border-box; + + &:hover { + &::after { + content: ""; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + box-shadow: 0 0 0 1px var(--color-gray-30); + border-radius: calc(var(--radius) + 1px); + filter: var(--theme-filter); + } + } + + &.active { + .color-picker__button-outline { + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + box-shadow: 0 0 0 1px var(--color-primary-darkest); + z-index: 1; // due hover state so this has preference + border-radius: calc(var(--radius) + 1px); + filter: var(--theme-filter); + } + } + + &:focus-visible { + outline: none; + + &::after { + content: ""; + position: absolute; + top: -4px; + right: -4px; + bottom: -4px; + left: -4px; + border: 3px solid var(--focus-highlight-color); + border-radius: calc(var(--radius) + 1px); + } + + &.active { + .color-picker__button-outline { + display: none; + } + } + } + + &--large { + --radius: 0.5rem; + width: 1.875rem; + height: 1.875rem; + } + + &.is-transparent { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg=="); + } + + &--no-focus-visible { + border: 0; + &::after { + display: none; + } + &:focus-visible { + outline: none !important; + } + } + + &.active-color { + border-radius: calc(var(--radius) + 1px); + width: 1.625rem; + height: 1.625rem; + } + } + + .color-picker__button__hotkey-label { + position: absolute; + right: 4px; + bottom: 4px; + filter: none; + font-size: 11px; + } + .color-picker { background: var(--popup-bg-color); border: 0 solid transparentize($oc-white, 0.75); @@ -72,11 +200,17 @@ } } + .color-picker-content { + display: flex; + flex-direction: column; + gap: 0.75rem; + } + .color-picker-content--default { padding: 0.5rem; display: grid; - grid-template-columns: repeat(5, auto); - grid-gap: 0.5rem; + grid-template-columns: repeat(5, 1.875rem); + grid-gap: 0.25rem; border-radius: 4px; &:focus { @@ -178,6 +312,27 @@ } } + .color-picker__input-label { + display: grid; + grid-template-columns: auto 1fr auto auto; + gap: 8px; + align-items: center; + border: 1px solid var(--default-border-color); + border-radius: 8px; + padding: 0 12px; + margin: 8px; + box-sizing: border-box; + + &:focus-within { + box-shadow: 0 0 0 1px var(--color-primary-darkest); + border-radius: var(--border-radius-lg); + } + } + + .color-picker__input-hash { + padding: 0 0.25rem; + } + .color-picker-input { box-sizing: border-box; width: 100%; diff --git a/src/components/ColorPicker/ColorPicker.tsx b/src/components/ColorPicker/ColorPicker.tsx new file mode 100644 index 000000000..25ac7c1a8 --- /dev/null +++ b/src/components/ColorPicker/ColorPicker.tsx @@ -0,0 +1,235 @@ +import { isTransparent } from "../../utils"; +import { ExcalidrawElement } from "../../element/types"; +import { AppState } from "../../types"; +import { TopPicks } from "./TopPicks"; +import { Picker } from "./Picker"; +import * as Popover from "@radix-ui/react-popover"; +import { useAtom } from "jotai"; +import { + activeColorPickerSectionAtom, + ColorPickerType, +} from "./colorPickerUtils"; +import { useDevice, useExcalidrawContainer } from "../App"; +import { ColorTuple, COLOR_PALETTE, ColorPaletteCustom } from "../../colors"; +import PickerHeading from "./PickerHeading"; +import { ColorInput } from "./ColorInput"; +import { t } from "../../i18n"; +import clsx from "clsx"; + +import "./ColorPicker.scss"; +import React from "react"; + +const isValidColor = (color: string) => { + const style = new Option().style; + style.color = color; + return !!style.color; +}; + +export const getColor = (color: string): string | null => { + if (isTransparent(color)) { + return color; + } + + // testing for `#` first fixes a bug on Electron (more specfically, an + // Obsidian popout window), where a hex color without `#` is (incorrectly) + // considered valid + return isValidColor(`#${color}`) + ? `#${color}` + : isValidColor(color) + ? color + : null; +}; + +export interface ColorPickerProps { + type: ColorPickerType; + color: string | null; + onChange: (color: string) => void; + label: string; + elements: readonly ExcalidrawElement[]; + appState: AppState; + palette?: ColorPaletteCustom | null; + topPicks?: ColorTuple; + updateData: (formData?: any) => void; +} + +const ColorPickerPopupContent = ({ + type, + color, + onChange, + label, + elements, + palette = COLOR_PALETTE, + updateData, +}: Pick< + ColorPickerProps, + | "type" + | "color" + | "onChange" + | "label" + | "label" + | "elements" + | "palette" + | "updateData" +>) => { + const [, setActiveColorPickerSection] = useAtom(activeColorPickerSectionAtom); + + const { container } = useExcalidrawContainer(); + const { isMobile, isLandscape } = useDevice(); + + const colorInputJSX = ( +
+ {t("colorPicker.hexCode")} + { + onChange(color); + }} + /> +
+ ); + + return ( + + { + // return focus to excalidraw container + if (container) { + container.focus(); + } + + e.preventDefault(); + e.stopPropagation(); + + setActiveColorPickerSection(null); + }} + side={isMobile && !isLandscape ? "bottom" : "right"} + align={isMobile && !isLandscape ? "center" : "start"} + alignOffset={-16} + sideOffset={20} + style={{ + zIndex: 9999, + backgroundColor: "var(--popup-bg-color)", + maxWidth: "208px", + maxHeight: window.innerHeight, + padding: "12px", + borderRadius: "8px", + boxSizing: "border-box", + overflowY: "auto", + boxShadow: + "0px 7px 14px rgba(0, 0, 0, 0.05), 0px 0px 3.12708px rgba(0, 0, 0, 0.0798), 0px 0px 0.931014px rgba(0, 0, 0, 0.1702)", + }} + > + {palette ? ( + { + onChange(changedColor); + }} + label={label} + type={type} + elements={elements} + updateData={updateData} + > + {colorInputJSX} + + ) : ( + colorInputJSX + )} + + + + ); +}; + +const ColorPickerTrigger = ({ + label, + color, + type, +}: { + color: string | null; + label: string; + type: ColorPickerType; +}) => { + return ( + +
+ + ); +}; + +export const ColorPicker = ({ + type, + color, + onChange, + label, + elements, + palette = COLOR_PALETTE, + topPicks, + updateData, + appState, +}: ColorPickerProps) => { + return ( +
+
+ +
+ { + updateData({ openPopup: open ? type : null }); + }} + > + {/* serves as an active color indicator as well */} + + {/* popup content */} + {appState.openPopup === type && ( + + )} + +
+
+ ); +}; diff --git a/src/components/ColorPicker/CustomColorList.tsx b/src/components/ColorPicker/CustomColorList.tsx new file mode 100644 index 000000000..f606482b8 --- /dev/null +++ b/src/components/ColorPicker/CustomColorList.tsx @@ -0,0 +1,63 @@ +import clsx from "clsx"; +import { useAtom } from "jotai"; +import { useEffect, useRef } from "react"; +import { activeColorPickerSectionAtom } from "./colorPickerUtils"; +import HotkeyLabel from "./HotkeyLabel"; + +interface CustomColorListProps { + colors: string[]; + color: string | null; + onChange: (color: string) => void; + label: string; +} + +export const CustomColorList = ({ + colors, + color, + onChange, + label, +}: CustomColorListProps) => { + const [activeColorPickerSection, setActiveColorPickerSection] = useAtom( + activeColorPickerSectionAtom, + ); + + const btnRef = useRef(null); + + useEffect(() => { + if (btnRef.current) { + btnRef.current.focus(); + } + }, [color, activeColorPickerSection]); + + return ( +
+ {colors.map((c, i) => { + return ( + + ); + })} +
+ ); +}; diff --git a/src/components/ColorPicker/HotkeyLabel.tsx b/src/components/ColorPicker/HotkeyLabel.tsx new file mode 100644 index 000000000..145060d19 --- /dev/null +++ b/src/components/ColorPicker/HotkeyLabel.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { getContrastYIQ } from "./colorPickerUtils"; + +interface HotkeyLabelProps { + color: string; + keyLabel: string | number; + isCustomColor?: boolean; + isShade?: boolean; +} +const HotkeyLabel = ({ + color, + keyLabel, + isCustomColor = false, + isShade = false, +}: HotkeyLabelProps) => { + return ( +
+ {isShade && "⇧"} + {keyLabel} +
+ ); +}; + +export default HotkeyLabel; diff --git a/src/components/ColorPicker/Picker.tsx b/src/components/ColorPicker/Picker.tsx new file mode 100644 index 000000000..be6410e13 --- /dev/null +++ b/src/components/ColorPicker/Picker.tsx @@ -0,0 +1,156 @@ +import React, { useEffect, useState } from "react"; +import { t } from "../../i18n"; + +import { ExcalidrawElement } from "../../element/types"; +import { ShadeList } from "./ShadeList"; + +import PickerColorList from "./PickerColorList"; +import { useAtom } from "jotai"; +import { CustomColorList } from "./CustomColorList"; +import { colorPickerKeyNavHandler } from "./keyboardNavHandlers"; +import PickerHeading from "./PickerHeading"; +import { + ColorPickerType, + activeColorPickerSectionAtom, + getColorNameAndShadeFromHex, + getMostUsedCustomColors, + isCustomColor, +} from "./colorPickerUtils"; +import { + ColorPaletteCustom, + DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX, + DEFAULT_ELEMENT_STROKE_COLOR_INDEX, +} from "../../colors"; + +interface PickerProps { + color: string | null; + onChange: (color: string) => void; + label: string; + type: ColorPickerType; + elements: readonly ExcalidrawElement[]; + palette: ColorPaletteCustom; + updateData: (formData?: any) => void; + children?: React.ReactNode; +} + +export const Picker = ({ + color, + onChange, + label, + type, + elements, + palette, + updateData, + children, +}: PickerProps) => { + const [customColors] = React.useState(() => { + if (type === "canvasBackground") { + return []; + } + return getMostUsedCustomColors(elements, type, palette); + }); + + const [activeColorPickerSection, setActiveColorPickerSection] = useAtom( + activeColorPickerSectionAtom, + ); + + const colorObj = getColorNameAndShadeFromHex({ + hex: color || "transparent", + palette, + }); + + useEffect(() => { + if (!activeColorPickerSection) { + const isCustom = isCustomColor({ color, palette }); + const isCustomButNotInList = + isCustom && !customColors.includes(color || ""); + + setActiveColorPickerSection( + isCustomButNotInList + ? "hex" + : isCustom + ? "custom" + : colorObj?.shade != null + ? "shades" + : "baseColors", + ); + } + }, [ + activeColorPickerSection, + color, + palette, + setActiveColorPickerSection, + colorObj, + customColors, + ]); + + const [activeShade, setActiveShade] = useState( + colorObj?.shade ?? + (type === "elementBackground" + ? DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX + : DEFAULT_ELEMENT_STROKE_COLOR_INDEX), + ); + + useEffect(() => { + if (colorObj?.shade != null) { + setActiveShade(colorObj.shade); + } + }, [colorObj]); + + return ( +
+
{ + e.preventDefault(); + e.stopPropagation(); + + colorPickerKeyNavHandler({ + e, + activeColorPickerSection, + palette, + hex: color, + onChange, + customColors, + setActiveColorPickerSection, + updateData, + activeShade, + }); + }} + className="color-picker-content" + // to allow focusing by clicking but not by tabbing + tabIndex={-1} + > + {!!customColors.length && ( +
+ + {t("colorPicker.mostUsedCustomColors")} + + +
+ )} + +
+ {t("colorPicker.colors")} + +
+ +
+ {t("colorPicker.shades")} + +
+ {children} +
+
+ ); +}; diff --git a/src/components/ColorPicker/PickerColorList.tsx b/src/components/ColorPicker/PickerColorList.tsx new file mode 100644 index 000000000..bd2d2bfcf --- /dev/null +++ b/src/components/ColorPicker/PickerColorList.tsx @@ -0,0 +1,86 @@ +import clsx from "clsx"; +import { useAtom } from "jotai"; +import { useEffect, useRef } from "react"; +import { + activeColorPickerSectionAtom, + colorPickerHotkeyBindings, + getColorNameAndShadeFromHex, +} from "./colorPickerUtils"; +import HotkeyLabel from "./HotkeyLabel"; +import { ColorPaletteCustom } from "../../colors"; +import { t } from "../../i18n"; + +interface PickerColorListProps { + palette: ColorPaletteCustom; + color: string | null; + onChange: (color: string) => void; + label: string; + activeShade: number; +} + +const PickerColorList = ({ + palette, + color, + onChange, + label, + activeShade, +}: PickerColorListProps) => { + const colorObj = getColorNameAndShadeFromHex({ + hex: color || "transparent", + palette, + }); + const [activeColorPickerSection, setActiveColorPickerSection] = useAtom( + activeColorPickerSectionAtom, + ); + + const btnRef = useRef(null); + + useEffect(() => { + if (btnRef.current && activeColorPickerSection === "baseColors") { + btnRef.current.focus(); + } + }, [colorObj?.colorName, activeColorPickerSection]); + + return ( +
+ {Object.entries(palette).map(([key, value], index) => { + const color = + (Array.isArray(value) ? value[activeShade] : value) || "transparent"; + + const keybinding = colorPickerHotkeyBindings[index]; + const label = t(`colors.${key.replace(/\d+/, "")}`, null, ""); + + return ( + + ); + })} +
+ ); +}; + +export default PickerColorList; diff --git a/src/components/ColorPicker/PickerHeading.tsx b/src/components/ColorPicker/PickerHeading.tsx new file mode 100644 index 000000000..043731366 --- /dev/null +++ b/src/components/ColorPicker/PickerHeading.tsx @@ -0,0 +1,7 @@ +import { ReactNode } from "react"; + +const PickerHeading = ({ children }: { children: ReactNode }) => ( +
{children}
+); + +export default PickerHeading; diff --git a/src/components/ColorPicker/ShadeList.tsx b/src/components/ColorPicker/ShadeList.tsx new file mode 100644 index 000000000..96c353e3d --- /dev/null +++ b/src/components/ColorPicker/ShadeList.tsx @@ -0,0 +1,105 @@ +import clsx from "clsx"; +import { useAtom } from "jotai"; +import { useEffect, useRef } from "react"; +import { + activeColorPickerSectionAtom, + getColorNameAndShadeFromHex, +} from "./colorPickerUtils"; +import HotkeyLabel from "./HotkeyLabel"; +import { t } from "../../i18n"; +import { ColorPaletteCustom } from "../../colors"; + +interface ShadeListProps { + hex: string | null; + onChange: (color: string) => void; + palette: ColorPaletteCustom; +} + +export const ShadeList = ({ hex, onChange, palette }: ShadeListProps) => { + const colorObj = getColorNameAndShadeFromHex({ + hex: hex || "transparent", + palette, + }); + + const [activeColorPickerSection, setActiveColorPickerSection] = useAtom( + activeColorPickerSectionAtom, + ); + + const btnRef = useRef(null); + + useEffect(() => { + if (btnRef.current && activeColorPickerSection === "shades") { + btnRef.current.focus(); + } + }, [colorObj, activeColorPickerSection]); + + if (colorObj) { + const { colorName, shade } = colorObj; + + const shades = palette[colorName]; + + if (Array.isArray(shades)) { + return ( +
+ {shades.map((color, i) => ( + + ))} +
+ ); + } + } + + return ( +
+
+ ); +}; diff --git a/src/components/ColorPicker/TopPicks.tsx b/src/components/ColorPicker/TopPicks.tsx new file mode 100644 index 000000000..3345632eb --- /dev/null +++ b/src/components/ColorPicker/TopPicks.tsx @@ -0,0 +1,64 @@ +import clsx from "clsx"; +import { ColorPickerType } from "./colorPickerUtils"; +import { + DEFAULT_CANVAS_BACKGROUND_PICKS, + DEFAULT_ELEMENT_BACKGROUND_PICKS, + DEFAULT_ELEMENT_STROKE_PICKS, +} from "../../colors"; + +interface TopPicksProps { + onChange: (color: string) => void; + type: ColorPickerType; + activeColor: string | null; + topPicks?: readonly string[]; +} + +export const TopPicks = ({ + onChange, + type, + activeColor, + topPicks, +}: TopPicksProps) => { + let colors; + if (type === "elementStroke") { + colors = DEFAULT_ELEMENT_STROKE_PICKS; + } + + if (type === "elementBackground") { + colors = DEFAULT_ELEMENT_BACKGROUND_PICKS; + } + + if (type === "canvasBackground") { + colors = DEFAULT_CANVAS_BACKGROUND_PICKS; + } + + // this one can overwrite defaults + if (topPicks) { + colors = topPicks; + } + + if (!colors) { + console.error("Invalid type for TopPicks"); + return null; + } + + return ( +
+ {colors.map((color: string) => ( + + ))} +
+ ); +}; diff --git a/src/components/ColorPicker/colorPickerUtils.ts b/src/components/ColorPicker/colorPickerUtils.ts new file mode 100644 index 000000000..4c4075b2a --- /dev/null +++ b/src/components/ColorPicker/colorPickerUtils.ts @@ -0,0 +1,139 @@ +import { ExcalidrawElement } from "../../element/types"; +import { atom } from "jotai"; +import { + ColorPickerColor, + ColorPaletteCustom, + MAX_CUSTOM_COLORS_USED_IN_CANVAS, +} from "../../colors"; + +export const getColorNameAndShadeFromHex = ({ + palette, + hex, +}: { + palette: ColorPaletteCustom; + hex: string; +}): { + colorName: ColorPickerColor; + shade: number | null; +} | null => { + for (const [colorName, colorVal] of Object.entries(palette)) { + if (Array.isArray(colorVal)) { + const shade = colorVal.indexOf(hex); + if (shade > -1) { + return { colorName: colorName as ColorPickerColor, shade }; + } + } else if (colorVal === hex) { + return { colorName: colorName as ColorPickerColor, shade: null }; + } + } + return null; +}; + +export const colorPickerHotkeyBindings = [ + ["q", "w", "e", "r", "t"], + ["a", "s", "d", "f", "g"], + ["z", "x", "c", "v", "b"], +].flat(); + +export const isCustomColor = ({ + color, + palette, +}: { + color: string | null; + palette: ColorPaletteCustom; +}) => { + if (!color) { + return false; + } + const paletteValues = Object.values(palette).flat(); + return !paletteValues.includes(color); +}; + +export const getMostUsedCustomColors = ( + elements: readonly ExcalidrawElement[], + type: "elementBackground" | "elementStroke", + palette: ColorPaletteCustom, +) => { + const elementColorTypeMap = { + elementBackground: "backgroundColor", + elementStroke: "strokeColor", + }; + + const colors = elements.filter((element) => { + if (element.isDeleted) { + return false; + } + + const color = + element[elementColorTypeMap[type] as "backgroundColor" | "strokeColor"]; + + return isCustomColor({ color, palette }); + }); + + const colorCountMap = new Map(); + colors.forEach((element) => { + const color = + element[elementColorTypeMap[type] as "backgroundColor" | "strokeColor"]; + if (colorCountMap.has(color)) { + colorCountMap.set(color, colorCountMap.get(color)! + 1); + } else { + colorCountMap.set(color, 1); + } + }); + + return [...colorCountMap.entries()] + .sort((a, b) => b[1] - a[1]) + .map((c) => c[0]) + .slice(0, MAX_CUSTOM_COLORS_USED_IN_CANVAS); +}; + +export type ActiveColorPickerSectionAtomType = + | "custom" + | "baseColors" + | "shades" + | "hex" + | null; +export const activeColorPickerSectionAtom = + atom(null); + +const calculateContrast = (r: number, g: number, b: number) => { + const yiq = (r * 299 + g * 587 + b * 114) / 1000; + return yiq >= 160 ? "black" : "white"; +}; + +// inspiration from https://stackoverflow.com/a/11868398 +export const getContrastYIQ = (bgHex: string, isCustomColor: boolean) => { + if (isCustomColor) { + const style = new Option().style; + style.color = bgHex; + + if (style.color) { + const rgb = style.color + .replace(/^(rgb|rgba)\(/, "") + .replace(/\)$/, "") + .replace(/\s/g, "") + .split(","); + const r = parseInt(rgb[0]); + const g = parseInt(rgb[1]); + const b = parseInt(rgb[2]); + + return calculateContrast(r, g, b); + } + } + + // TODO: ? is this wanted? + if (bgHex === "transparent") { + return "black"; + } + + const r = parseInt(bgHex.substring(1, 3), 16); + const g = parseInt(bgHex.substring(3, 5), 16); + const b = parseInt(bgHex.substring(5, 7), 16); + + return calculateContrast(r, g, b); +}; + +export type ColorPickerType = + | "canvasBackground" + | "elementBackground" + | "elementStroke"; diff --git a/src/components/ColorPicker/keyboardNavHandlers.ts b/src/components/ColorPicker/keyboardNavHandlers.ts new file mode 100644 index 000000000..4ed539cee --- /dev/null +++ b/src/components/ColorPicker/keyboardNavHandlers.ts @@ -0,0 +1,249 @@ +import { + ColorPickerColor, + ColorPalette, + ColorPaletteCustom, + COLORS_PER_ROW, + COLOR_PALETTE, +} from "../../colors"; +import { KEYS } from "../../keys"; +import { ValueOf } from "../../utility-types"; +import { + ActiveColorPickerSectionAtomType, + colorPickerHotkeyBindings, + getColorNameAndShadeFromHex, +} from "./colorPickerUtils"; + +const arrowHandler = ( + eventKey: string, + currentIndex: number | null, + length: number, +) => { + const rows = Math.ceil(length / COLORS_PER_ROW); + + currentIndex = currentIndex ?? -1; + + switch (eventKey) { + case "ArrowLeft": { + const prevIndex = currentIndex - 1; + return prevIndex < 0 ? length - 1 : prevIndex; + } + case "ArrowRight": { + return (currentIndex + 1) % length; + } + case "ArrowDown": { + const nextIndex = currentIndex + COLORS_PER_ROW; + return nextIndex >= length ? currentIndex % COLORS_PER_ROW : nextIndex; + } + case "ArrowUp": { + const prevIndex = currentIndex - COLORS_PER_ROW; + const newIndex = + prevIndex < 0 ? COLORS_PER_ROW * rows + prevIndex : prevIndex; + return newIndex >= length ? undefined : newIndex; + } + } +}; + +interface HotkeyHandlerProps { + e: React.KeyboardEvent; + colorObj: { colorName: ColorPickerColor; shade: number | null } | null; + onChange: (color: string) => void; + palette: ColorPaletteCustom; + customColors: string[]; + setActiveColorPickerSection: ( + update: React.SetStateAction, + ) => void; + activeShade: number; +} + +const hotkeyHandler = ({ + e, + colorObj, + onChange, + palette, + customColors, + setActiveColorPickerSection, + activeShade, +}: HotkeyHandlerProps) => { + if (colorObj?.shade != null) { + // shift + numpad is extremely messed up on windows apparently + if ( + ["Digit1", "Digit2", "Digit3", "Digit4", "Digit5"].includes(e.code) && + e.shiftKey + ) { + const newShade = Number(e.code.slice(-1)) - 1; + onChange(palette[colorObj.colorName][newShade]); + setActiveColorPickerSection("shades"); + } + } + + if (["1", "2", "3", "4", "5"].includes(e.key)) { + const c = customColors[Number(e.key) - 1]; + if (c) { + onChange(customColors[Number(e.key) - 1]); + setActiveColorPickerSection("custom"); + } + } + + if (colorPickerHotkeyBindings.includes(e.key)) { + const index = colorPickerHotkeyBindings.indexOf(e.key); + const paletteKey = Object.keys(palette)[index] as keyof ColorPalette; + const paletteValue = palette[paletteKey]; + const r = Array.isArray(paletteValue) + ? paletteValue[activeShade] + : paletteValue; + onChange(r); + setActiveColorPickerSection("baseColors"); + } +}; + +interface ColorPickerKeyNavHandlerProps { + e: React.KeyboardEvent; + activeColorPickerSection: ActiveColorPickerSectionAtomType; + palette: ColorPaletteCustom; + hex: string | null; + onChange: (color: string) => void; + customColors: string[]; + setActiveColorPickerSection: ( + update: React.SetStateAction, + ) => void; + updateData: (formData?: any) => void; + activeShade: number; +} + +export const colorPickerKeyNavHandler = ({ + e, + activeColorPickerSection, + palette, + hex, + onChange, + customColors, + setActiveColorPickerSection, + updateData, + activeShade, +}: ColorPickerKeyNavHandlerProps) => { + if (e.key === KEYS.ESCAPE || !hex) { + updateData({ openPopup: null }); + return; + } + + const colorObj = getColorNameAndShadeFromHex({ hex, palette }); + + if (e.key === KEYS.TAB) { + const sectionsMap: Record< + NonNullable, + boolean + > = { + custom: !!customColors.length, + baseColors: true, + shades: colorObj?.shade != null, + hex: true, + }; + + const sections = Object.entries(sectionsMap).reduce((acc, [key, value]) => { + if (value) { + acc.push(key as ActiveColorPickerSectionAtomType); + } + return acc; + }, [] as ActiveColorPickerSectionAtomType[]); + + const activeSectionIndex = sections.indexOf(activeColorPickerSection); + const indexOffset = e.shiftKey ? -1 : 1; + const nextSectionIndex = + activeSectionIndex + indexOffset > sections.length - 1 + ? 0 + : activeSectionIndex + indexOffset < 0 + ? sections.length - 1 + : activeSectionIndex + indexOffset; + + const nextSection = sections[nextSectionIndex]; + + if (nextSection) { + setActiveColorPickerSection(nextSection); + } + + if (nextSection === "custom") { + onChange(customColors[0]); + } else if (nextSection === "baseColors") { + const baseColorName = ( + Object.entries(palette) as [string, ValueOf][] + ).find(([name, shades]) => { + if (Array.isArray(shades)) { + return shades.includes(hex); + } else if (shades === hex) { + return name; + } + return null; + }); + + if (!baseColorName) { + onChange(COLOR_PALETTE.black); + } + } + + e.preventDefault(); + e.stopPropagation(); + + return; + } + + hotkeyHandler({ + e, + colorObj, + onChange, + palette, + customColors, + setActiveColorPickerSection, + activeShade, + }); + + if (activeColorPickerSection === "shades") { + if (colorObj) { + const { shade } = colorObj; + const newShade = arrowHandler(e.key, shade, COLORS_PER_ROW); + + if (newShade !== undefined) { + onChange(palette[colorObj.colorName][newShade]); + } + } + } + + if (activeColorPickerSection === "baseColors") { + if (colorObj) { + const { colorName } = colorObj; + const colorNames = Object.keys(palette) as (keyof ColorPalette)[]; + const indexOfColorName = colorNames.indexOf(colorName); + + const newColorIndex = arrowHandler( + e.key, + indexOfColorName, + colorNames.length, + ); + + if (newColorIndex !== undefined) { + const newColorName = colorNames[newColorIndex]; + const newColorNameValue = palette[newColorName]; + + onChange( + Array.isArray(newColorNameValue) + ? newColorNameValue[activeShade] + : newColorNameValue, + ); + } + } + } + + if (activeColorPickerSection === "custom") { + const indexOfColor = customColors.indexOf(hex); + + const newColorIndex = arrowHandler( + e.key, + indexOfColor, + customColors.length, + ); + + if (newColorIndex !== undefined) { + const newColor = customColors[newColorIndex]; + onChange(newColor); + } + } +}; diff --git a/src/components/LibraryUnit.tsx b/src/components/LibraryUnit.tsx index 749877cdd..7e8181d7b 100644 --- a/src/components/LibraryUnit.tsx +++ b/src/components/LibraryUnit.tsx @@ -1,5 +1,4 @@ import clsx from "clsx"; -import oc from "open-color"; import { useEffect, useRef, useState } from "react"; import { useDevice } from "../components/App"; import { exportToSvg } from "../packages/utils"; @@ -7,6 +6,7 @@ import { LibraryItem } from "../types"; import "./LibraryUnit.scss"; import { CheckboxItem } from "./CheckboxItem"; import { PlusIcon } from "./icons"; +import { COLOR_PALETTE } from "../colors"; export const LibraryUnit = ({ id, @@ -40,7 +40,7 @@ export const LibraryUnit = ({ elements, appState: { exportBackground: false, - viewBackgroundColor: oc.white, + viewBackgroundColor: COLOR_PALETTE.white, }, files: null, }); diff --git a/src/components/ProjectName.tsx b/src/components/ProjectName.tsx index db2b70027..47a77ac4c 100644 --- a/src/components/ProjectName.tsx +++ b/src/components/ProjectName.tsx @@ -5,6 +5,7 @@ import { focusNearestParent } from "../utils"; import "./ProjectName.scss"; import { useExcalidrawContainer } from "./App"; +import { KEYS } from "../keys"; type Props = { value: string; @@ -26,7 +27,7 @@ export const ProjectName = (props: Props) => { }; const handleKeyDown = (event: React.KeyboardEvent) => { - if (event.key === "Enter") { + if (event.key === KEYS.ENTER) { event.preventDefault(); if (event.nativeEvent.isComposing || event.keyCode === 229) { return; diff --git a/src/components/dropdownMenu/DropdownMenuContent.tsx b/src/components/dropdownMenu/DropdownMenuContent.tsx index 3c50d474c..7585649c8 100644 --- a/src/components/dropdownMenu/DropdownMenuContent.tsx +++ b/src/components/dropdownMenu/DropdownMenuContent.tsx @@ -48,7 +48,7 @@ const MenuContent = ({ {children} diff --git a/src/constants.ts b/src/constants.ts index e7241e175..3b21dd40f 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,7 +1,7 @@ import cssVariables from "./css/variables.module.scss"; import { AppProps } from "./types"; import { ExcalidrawElement, FontFamilyValues } from "./element/types"; -import oc from "open-color"; +import { COLOR_PALETTE } from "./colors"; export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform); export const isWindows = /^Win/.test(navigator.platform); @@ -272,8 +272,8 @@ export const DEFAULT_ELEMENT_PROPS: { opacity: ExcalidrawElement["opacity"]; locked: ExcalidrawElement["locked"]; } = { - strokeColor: oc.black, - backgroundColor: "transparent", + strokeColor: COLOR_PALETTE.black, + backgroundColor: COLOR_PALETTE.transparent, fillStyle: "hachure", strokeWidth: 1, strokeStyle: "solid", diff --git a/src/data/restore.ts b/src/data/restore.ts index 63f3dbcfb..96f30aaeb 100644 --- a/src/data/restore.ts +++ b/src/data/restore.ts @@ -34,13 +34,13 @@ import { LinearElementEditor } from "../element/linearElementEditor"; import { bumpVersion } from "../element/mutateElement"; import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils"; import { arrayToMap } from "../utils"; -import oc from "open-color"; import { MarkOptional, Mutable } from "../utility-types"; import { detectLineHeight, getDefaultLineHeight, measureBaseline, } from "../element/textElement"; +import { COLOR_PALETTE } from "../colors"; type RestoredAppState = Omit< AppState, @@ -119,8 +119,8 @@ const restoreElementWithProperties = < angle: element.angle || 0, x: extra.x ?? element.x ?? 0, y: extra.y ?? element.y ?? 0, - strokeColor: element.strokeColor || oc.black, - backgroundColor: element.backgroundColor || "transparent", + strokeColor: element.strokeColor || COLOR_PALETTE.black, + backgroundColor: element.backgroundColor || COLOR_PALETTE.transparent, width: element.width || 0, height: element.height || 0, seed: element.seed ?? 1, diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx index f3c75db8b..294c13263 100644 --- a/src/element/textWysiwyg.test.tsx +++ b/src/element/textWysiwyg.test.tsx @@ -1521,7 +1521,7 @@ describe("textWysiwyg", () => { roundness: { type: 3, }, - strokeColor: "#000000", + strokeColor: "#1e1e1e", strokeStyle: "solid", strokeWidth: 1, type: "rectangle", diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index d5fa0aadd..5b94ab3e8 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -636,20 +636,46 @@ export const textWysiwyg = ({ // in that same tick. const target = event?.target; - const isTargetColorPicker = - target instanceof HTMLInputElement && - target.closest(".color-picker-input") && - isWritableElement(target); + const isTargetPickerTrigger = + target instanceof HTMLElement && + target.classList.contains("active-color"); setTimeout(() => { editable.onblur = handleSubmit; - if (target && isTargetColorPicker) { - target.onblur = () => { - editable.focus(); + + if (isTargetPickerTrigger) { + const callback = ( + mutationList: MutationRecord[], + observer: MutationObserver, + ) => { + const radixIsRemoved = mutationList.find( + (mutation) => + mutation.removedNodes.length > 0 && + (mutation.removedNodes[0] as HTMLElement).dataset + ?.radixPopperContentWrapper !== undefined, + ); + + if (radixIsRemoved) { + // should work without this in theory + // and i think it does actually but radix probably somewhere, + // somehow sets the focus elsewhere + setTimeout(() => { + editable.focus(); + }); + + observer.disconnect(); + } }; + + const observer = new MutationObserver(callback); + + observer.observe(document.querySelector(".excalidraw-container")!, { + childList: true, + }); } + // case: clicking on the same property → no change → no update → no focus - if (!isTargetColorPicker) { + if (!isTargetPickerTrigger) { editable.focus(); } }); @@ -657,16 +683,16 @@ export const textWysiwyg = ({ // prevent blur when changing properties from the menu const onPointerDown = (event: MouseEvent) => { - const isTargetColorPicker = - event.target instanceof HTMLInputElement && - event.target.closest(".color-picker-input") && - isWritableElement(event.target); + const isTargetPickerTrigger = + event.target instanceof HTMLElement && + event.target.classList.contains("active-color"); + if ( ((event.target instanceof HTMLElement || event.target instanceof SVGElement) && event.target.closest(`.${CLASSES.SHAPE_ACTIONS_MENU}`) && !isWritableElement(event.target)) || - isTargetColorPicker + isTargetPickerTrigger ) { editable.onblur = null; window.addEventListener("pointerup", bindBlurEvent); @@ -680,7 +706,7 @@ export const textWysiwyg = ({ const unbindUpdate = Scene.getScene(element)!.addCallback(() => { updateWysiwygStyle(); const isColorPickerActive = !!document.activeElement?.closest( - ".color-picker-input", + ".color-picker-content", ); if (!isColorPickerActive) { editable.focus(); diff --git a/src/excalidraw-app/collab/RoomDialog.tsx b/src/excalidraw-app/collab/RoomDialog.tsx index 42c123302..4810b5a55 100644 --- a/src/excalidraw-app/collab/RoomDialog.tsx +++ b/src/excalidraw-app/collab/RoomDialog.tsx @@ -17,6 +17,7 @@ import { trackEvent } from "../../analytics"; import { getFrame } from "../../utils"; import DialogActionButton from "../../components/DialogActionButton"; import { useI18n } from "../../i18n"; +import { KEYS } from "../../keys"; const getShareIcon = () => { const navigator = window.navigator as any; @@ -148,7 +149,9 @@ const RoomDialog = ({ value={username.trim() || ""} className="RoomDialog-username TextInput" onChange={(event) => onUsernameChange(event.target.value)} - onKeyPress={(event) => event.key === "Enter" && handleClose()} + onKeyPress={(event) => + event.key === KEYS.ENTER && handleClose() + } />

diff --git a/src/i18n.ts b/src/i18n.ts index 40d5884b8..7c688b210 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -124,7 +124,8 @@ const findPartsForData = (data: any, parts: string[]) => { export const t = ( path: string, - replacement?: { [key: string]: string | number }, + replacement?: { [key: string]: string | number } | null, + fallback?: string, ) => { if (currentLang.code.startsWith(TEST_LANG_CODE)) { const name = replacement @@ -136,9 +137,16 @@ export const t = ( const parts = path.split("."); let translation = findPartsForData(currentLangData, parts) || - findPartsForData(fallbackLangData, parts); + findPartsForData(fallbackLangData, parts) || + fallback; if (translation === undefined) { - throw new Error(`Can't find translation for ${path}`); + const errorMessage = `Can't find translation for ${path}`; + // in production, don't blow up the app on a missing translation key + if (process.env.NODE_ENV === "production") { + console.warn(errorMessage); + return ""; + } + throw new Error(errorMessage); } if (replacement) { diff --git a/src/locales/en.json b/src/locales/en.json index 136a0bc80..edc360142 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Use {{shortcut}} to paste as a single element,\nor paste into an existing text editor" }, "colors": { - "ffffff": "White", - "f8f9fa": "Gray 0", - "f1f3f5": "Gray 1", - "fff5f5": "Red 0", - "fff0f6": "Pink 0", - "f8f0fc": "Grape 0", - "f3f0ff": "Violet 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Blue 0", - "e3fafc": "Cyan 0", - "e6fcf5": "Teal 0", - "ebfbee": "Green 0", - "f4fce3": "Lime 0", - "fff9db": "Yellow 0", - "fff4e6": "Orange 0", "transparent": "Transparent", - "ced4da": "Gray 4", - "868e96": "Gray 6", - "fa5252": "Red 6", - "e64980": "Pink 6", - "be4bdb": "Grape 6", - "7950f2": "Violet 6", - "4c6ef5": "Indigo 6", - "228be6": "Blue 6", - "15aabf": "Cyan 6", - "12b886": "Teal 6", - "40c057": "Green 6", - "82c91e": "Lime 6", - "fab005": "Yellow 6", - "fd7e14": "Orange 6", - "000000": "Black", - "343a40": "Gray 8", - "495057": "Gray 7", - "c92a2a": "Red 9", - "a61e4d": "Pink 9", - "862e9c": "Grape 9", - "5f3dc4": "Violet 9", - "364fc7": "Indigo 9", - "1864ab": "Blue 9", - "0b7285": "Cyan 9", - "087f5b": "Teal 9", - "2b8a3e": "Green 9", - "5c940d": "Lime 9", - "e67700": "Yellow 9", - "d9480f": "Orange 9" + "black": "Black", + "white": "White", + "red": "Red", + "pink": "Pink", + "grape": "Grape", + "violet": "Violet", + "gray": "Gray", + "blue": "Blue", + "cyan": "Cyan", + "teal": "Teal", + "green": "Green", + "yellow": "Yellow", + "orange": "Orange", + "bronze": "Bronze" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Pick a tool & Start drawing!", "helpHint": "Shortcuts & help" } + }, + "colorPicker": { + "mostUsedCustomColors": "Most used custom colors", + "colors": "Colors", + "shades": "Shades", + "hexCode": "Hex code", + "noShades": "No shades available for this color" } } diff --git a/src/packages/excalidraw/example/App.tsx b/src/packages/excalidraw/example/App.tsx index 3a0634e63..bccb42bdc 100644 --- a/src/packages/excalidraw/example/App.tsx +++ b/src/packages/excalidraw/example/App.tsx @@ -30,6 +30,7 @@ import { NonDeletedExcalidrawElement } from "../../../element/types"; import { ImportedLibraryData } from "../../../data/types"; import CustomFooter from "./CustomFooter"; import MobileFooter from "./MobileFooter"; +import { KEYS } from "../../../keys"; declare global { interface Window { @@ -55,9 +56,9 @@ type PointerDownState = { y: number; }; }; + // This is so that we use the bundled excalidraw.development.js file instead // of the actual source code - const { exportToCanvas, exportToSvg, @@ -484,7 +485,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) { }} onBlur={saveComment} onKeyDown={(event) => { - if (!event.shiftKey && event.key === "Enter") { + if (!event.shiftKey && event.key === KEYS.ENTER) { event.preventDefault(); saveComment(); } @@ -521,9 +522,11 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) { ); }; + return (

{appTitle}

+ {/* TODO fix type */}
diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index 57f6ce395..9b6acfdd8 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -63,7 +63,7 @@ "sass-loader": "13.0.2", "terser-webpack-plugin": "5.3.3", "ts-loader": "9.3.1", - "typescript": "4.7.4", + "typescript": "4.9.4", "webpack": "5.76.0", "webpack-bundle-analyzer": "4.5.0", "webpack-cli": "4.10.0", diff --git a/src/packages/excalidraw/yarn.lock b/src/packages/excalidraw/yarn.lock index 339cda939..485d3cd00 100644 --- a/src/packages/excalidraw/yarn.lock +++ b/src/packages/excalidraw/yarn.lock @@ -3678,10 +3678,10 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@4.7.4: - version "4.7.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" - integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== +typescript@4.9.4: + version "4.9.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" + integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg== unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" diff --git a/src/tests/MobileMenu.test.tsx b/src/tests/MobileMenu.test.tsx index 41d5d0169..60059cb2e 100644 --- a/src/tests/MobileMenu.test.tsx +++ b/src/tests/MobileMenu.test.tsx @@ -29,6 +29,7 @@ describe("Test MobileMenu", () => { expect(h.app.device).toMatchInlineSnapshot(` Object { "canDeviceFitSidebar": false, + "isLandscape": true, "isMobile": true, "isSmScreen": false, "isTouchScreen": false, diff --git a/src/tests/__snapshots__/contextmenu.test.tsx.snap b/src/tests/__snapshots__/contextmenu.test.tsx.snap index 5b69dbe08..5e3a5b221 100644 --- a/src/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/src/tests/__snapshots__/contextmenu.test.tsx.snap @@ -279,7 +279,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -369,7 +369,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -402,7 +402,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -459,7 +459,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -546,7 +546,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -604,7 +604,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -645,7 +645,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -730,7 +730,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -761,7 +761,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -819,7 +819,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -861,7 +861,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -889,7 +889,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -931,7 +931,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -959,7 +959,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1000,7 +1000,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -1085,7 +1085,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1116,7 +1116,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1174,7 +1174,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1216,7 +1216,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1244,7 +1244,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1286,7 +1286,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1314,7 +1314,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1355,7 +1355,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -1442,7 +1442,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1500,7 +1500,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1541,7 +1541,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -1623,14 +1623,14 @@ Object { "roundness": Object { "type": 3, }, - "seed": 337897, - "strokeColor": "#000000", + "seed": 1278240551, + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 449462985, + "versionNonce": 453191, "width": 20, "x": -10, "y": 0, @@ -1681,14 +1681,14 @@ Object { "roundness": Object { "type": 3, }, - "seed": 337897, - "strokeColor": "#000000", + "seed": 1278240551, + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", "updated": 1, "version": 2, - "versionNonce": 1278240551, + "versionNonce": 449462985, "width": 20, "x": -10, "y": 0, @@ -1721,14 +1721,14 @@ Object { "roundness": Object { "type": 3, }, - "seed": 337897, - "strokeColor": "#000000", + "seed": 1278240551, + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 449462985, + "versionNonce": 453191, "width": 20, "x": -10, "y": 0, @@ -1763,7 +1763,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -1848,7 +1848,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1879,7 +1879,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1937,7 +1937,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1979,7 +1979,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2007,7 +2007,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2048,7 +2048,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -2141,7 +2141,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2174,7 +2174,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2232,7 +2232,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2274,7 +2274,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2302,7 +2302,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2350,7 +2350,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2380,7 +2380,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2412,7 +2412,7 @@ Object { "collaborators": Map {}, "contextMenu": null, "currentChartType": "bar", - "currentItemBackgroundColor": "#e64980", + "currentItemBackgroundColor": "#a5d8ff", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "cross-hatch", "currentItemFontFamily": 1, @@ -2421,7 +2421,7 @@ Object { "currentItemRoughness": 2, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#c92a2a", + "currentItemStrokeColor": "#e03131", "currentItemStrokeStyle": "dotted", "currentItemStrokeWidth": 2, "currentItemTextAlign": "left", @@ -2450,7 +2450,7 @@ Object { "offsetTop": 10, "openDialog": null, "openMenu": null, - "openPopup": "backgroundColorPicker", + "openPopup": null, "openSidebar": null, "pasteDialog": Object { "data": null, @@ -2493,7 +2493,7 @@ Object { exports[`contextMenu element selecting 'Paste styles' in context menu pastes styles: [end of test] element 0 1`] = ` Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -2508,7 +2508,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", @@ -2524,7 +2524,7 @@ Object { exports[`contextMenu element selecting 'Paste styles' in context menu pastes styles: [end of test] element 1 1`] = ` Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -2539,7 +2539,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", @@ -2597,7 +2597,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2639,7 +2639,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2667,7 +2667,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2709,7 +2709,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2737,7 +2737,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2779,7 +2779,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2792,7 +2792,7 @@ Object { }, Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], @@ -2807,7 +2807,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2849,7 +2849,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2862,7 +2862,7 @@ Object { }, Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -2877,7 +2877,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2919,7 +2919,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2932,7 +2932,7 @@ Object { }, Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -2947,7 +2947,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", @@ -2989,7 +2989,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3002,7 +3002,7 @@ Object { }, Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -3017,7 +3017,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", @@ -3059,7 +3059,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3072,7 +3072,7 @@ Object { }, Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -3087,7 +3087,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", @@ -3129,7 +3129,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3142,7 +3142,7 @@ Object { }, Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -3157,7 +3157,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", @@ -3184,7 +3184,7 @@ Object { "elements": Array [ Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -3199,7 +3199,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", @@ -3212,7 +3212,7 @@ Object { }, Object { "angle": 0, - "backgroundColor": "#e64980", + "backgroundColor": "#a5d8ff", "boundElements": null, "fillStyle": "cross-hatch", "groupIds": Array [], @@ -3227,7 +3227,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#c92a2a", + "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", @@ -3246,7 +3246,7 @@ Object { exports[`contextMenu element selecting 'Paste styles' in context menu pastes styles: [end of test] number of elements 1`] = `2`; -exports[`contextMenu element selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `33`; +exports[`contextMenu element selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `32`; exports[`contextMenu element selecting 'Send backward' in context menu sends element backward: [end of test] appState 1`] = ` Object { @@ -3268,7 +3268,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -3353,7 +3353,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3384,7 +3384,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3442,7 +3442,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3484,7 +3484,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3512,7 +3512,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3554,7 +3554,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3582,7 +3582,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3623,7 +3623,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -3708,7 +3708,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3739,7 +3739,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3797,7 +3797,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3839,7 +3839,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3867,7 +3867,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3909,7 +3909,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3937,7 +3937,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3978,7 +3978,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -4067,7 +4067,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4098,7 +4098,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4156,7 +4156,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4198,7 +4198,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4226,7 +4226,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4274,7 +4274,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4304,7 +4304,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4348,7 +4348,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4376,7 +4376,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4676,7 +4676,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -4767,7 +4767,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4798,7 +4798,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4856,7 +4856,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4898,7 +4898,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4926,7 +4926,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5226,7 +5226,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -5321,7 +5321,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5354,7 +5354,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5412,7 +5412,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5454,7 +5454,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5482,7 +5482,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5531,7 +5531,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5561,7 +5561,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5717,7 +5717,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -6085,7 +6085,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -6431,7 +6431,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -6516,7 +6516,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6547,7 +6547,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6578,7 +6578,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6636,7 +6636,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", diff --git a/src/tests/__snapshots__/dragCreate.test.tsx.snap b/src/tests/__snapshots__/dragCreate.test.tsx.snap index ffcf57b0d..4508fd3c7 100644 --- a/src/tests/__snapshots__/dragCreate.test.tsx.snap +++ b/src/tests/__snapshots__/dragCreate.test.tsx.snap @@ -35,7 +35,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -68,7 +68,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -101,7 +101,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -147,7 +147,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -180,7 +180,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", diff --git a/src/tests/__snapshots__/linearElementEditor.test.tsx.snap b/src/tests/__snapshots__/linearElementEditor.test.tsx.snap index a2f142b66..d1a73e72f 100644 --- a/src/tests/__snapshots__/linearElementEditor.test.tsx.snap +++ b/src/tests/__snapshots__/linearElementEditor.test.tsx.snap @@ -5,7 +5,7 @@ exports[`Test Linear Elements Test bound text element should match styles for te class="excalidraw-wysiwyg" data-type="wysiwyg" dir="auto" - style="position: absolute; display: inline-block; min-height: 1em; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 25px; left: 35px; top: 7.5px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(0, 0, 0); opacity: 1; filter: var(--theme-filter); max-height: -7.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Virgil, Segoe UI Emoji;" + style="position: absolute; display: inline-block; min-height: 1em; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 25px; left: 35px; top: 7.5px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(30, 30, 30); opacity: 1; filter: var(--theme-filter); max-height: -7.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Virgil, Segoe UI Emoji;" tabindex="0" wrap="off" /> diff --git a/src/tests/__snapshots__/move.test.tsx.snap b/src/tests/__snapshots__/move.test.tsx.snap index 7c0eed29b..b214243c5 100644 --- a/src/tests/__snapshots__/move.test.tsx.snap +++ b/src/tests/__snapshots__/move.test.tsx.snap @@ -18,7 +18,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -49,7 +49,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -80,7 +80,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -116,7 +116,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -152,7 +152,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -206,7 +206,7 @@ Object { "focus": -0.6000000000000001, "gap": 10, }, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", diff --git a/src/tests/__snapshots__/multiPointCreate.test.tsx.snap b/src/tests/__snapshots__/multiPointCreate.test.tsx.snap index 03ef0d26b..a1ce56362 100644 --- a/src/tests/__snapshots__/multiPointCreate.test.tsx.snap +++ b/src/tests/__snapshots__/multiPointCreate.test.tsx.snap @@ -40,7 +40,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -93,7 +93,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index 82d3dbbff..68d87ef33 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -20,7 +20,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -116,7 +116,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -149,7 +149,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -182,7 +182,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -240,7 +240,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -282,7 +282,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -310,7 +310,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -352,7 +352,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -380,7 +380,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -408,7 +408,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -455,7 +455,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -485,7 +485,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -515,7 +515,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -556,7 +556,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -659,7 +659,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -692,7 +692,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -725,7 +725,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -783,7 +783,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -825,7 +825,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -853,7 +853,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -895,7 +895,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -923,7 +923,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -951,7 +951,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -997,7 +997,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1027,7 +1027,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1057,7 +1057,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1098,7 +1098,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -1187,7 +1187,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1221,7 +1221,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1254,7 +1254,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1312,7 +1312,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1354,7 +1354,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1382,7 +1382,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1431,7 +1431,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1461,7 +1461,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1506,7 +1506,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1536,7 +1536,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1580,7 +1580,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1610,7 +1610,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1638,7 +1638,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1689,7 +1689,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1720,7 +1720,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1750,7 +1750,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1796,7 +1796,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1827,7 +1827,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1857,7 +1857,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1903,7 +1903,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1934,7 +1934,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -1964,7 +1964,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2005,7 +2005,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -2093,7 +2093,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -2151,7 +2151,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -2194,7 +2194,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -2235,7 +2235,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -2328,7 +2328,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2361,7 +2361,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2394,7 +2394,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2452,7 +2452,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2494,7 +2494,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2522,7 +2522,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2564,7 +2564,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2592,7 +2592,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2620,7 +2620,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2667,7 +2667,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2697,7 +2697,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2727,7 +2727,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2768,7 +2768,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -2856,7 +2856,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2887,7 +2887,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2945,7 +2945,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -2988,7 +2988,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3016,7 +3016,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3057,7 +3057,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -3142,7 +3142,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3200,7 +3200,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3241,7 +3241,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -3329,7 +3329,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3360,7 +3360,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3391,7 +3391,7 @@ Object { "type": 2, }, "seed": 2019559783, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -3449,7 +3449,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3491,7 +3491,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3519,7 +3519,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3561,7 +3561,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3589,7 +3589,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3617,7 +3617,7 @@ Object { "type": 2, }, "seed": 2019559783, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -3660,7 +3660,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3688,7 +3688,7 @@ Object { "type": 3, }, "seed": 453191, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3716,7 +3716,7 @@ Object { "type": 2, }, "seed": 2019559783, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -3748,7 +3748,7 @@ Object { "collaborators": Map {}, "contextMenu": null, "currentChartType": "bar", - "currentItemBackgroundColor": "#fa5252", + "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -3757,7 +3757,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#5f3dc4", + "currentItemStrokeColor": "#1971c2", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -3786,7 +3786,7 @@ Object { "offsetTop": 0, "openDialog": null, "openMenu": null, - "openPopup": "strokeColorPicker", + "openPopup": "elementStroke", "openSidebar": null, "pasteDialog": Object { "data": null, @@ -3827,7 +3827,7 @@ Object { exports[`regression tests change the properties of a shape: [end of test] element 0 1`] = ` Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], @@ -3842,13 +3842,13 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#5f3dc4", + "strokeColor": "#1971c2", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", "updated": 1, - "version": 4, - "versionNonce": 453191, + "version": 5, + "versionNonce": 401146281, "width": 10, "x": 10, "y": 10, @@ -3900,7 +3900,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3927,7 +3927,7 @@ Object { "elements": Array [ Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffec99", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], @@ -3942,7 +3942,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3969,7 +3969,7 @@ Object { "elements": Array [ Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], @@ -3984,7 +3984,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#5f3dc4", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -3997,13 +3997,55 @@ Object { }, ], }, + Object { + "appState": Object { + "editingGroupId": null, + "editingLinearElement": null, + "name": "Untitled-201933152653", + "selectedElementIds": Object { + "id0": true, + }, + "selectedGroupIds": Object {}, + "viewBackgroundColor": "#ffffff", + }, + "elements": Array [ + Object { + "angle": 0, + "backgroundColor": "#ffc9c9", + "boundElements": null, + "fillStyle": "hachure", + "groupIds": Array [], + "height": 10, + "id": "id0", + "isDeleted": false, + "link": null, + "locked": false, + "opacity": 100, + "roughness": 1, + "roundness": Object { + "type": 3, + }, + "seed": 337897, + "strokeColor": "#1971c2", + "strokeStyle": "solid", + "strokeWidth": 1, + "type": "rectangle", + "updated": 1, + "version": 5, + "versionNonce": 401146281, + "width": 10, + "x": 10, + "y": 10, + }, + ], + }, ], } `; 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`] = `15`; +exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `14`; exports[`regression tests click on an element and drag it: [dragged] appState 1`] = ` Object { @@ -4025,7 +4067,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -4113,7 +4155,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4171,7 +4213,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4214,7 +4256,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4255,7 +4297,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -4345,7 +4387,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4403,7 +4445,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4446,7 +4488,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4490,7 +4532,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4531,7 +4573,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -4619,7 +4661,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4650,7 +4692,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4708,7 +4750,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4750,7 +4792,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4778,7 +4820,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4819,7 +4861,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -4908,7 +4950,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4939,7 +4981,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -4970,7 +5012,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5028,7 +5070,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5070,7 +5112,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5098,7 +5140,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5140,7 +5182,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5168,7 +5210,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5196,7 +5238,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5237,7 +5279,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -5260,7 +5302,7 @@ Object { "type": 2, }, "seed": 2019559783, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -5331,7 +5373,7 @@ Object { "type": 2, }, "seed": 2019559783, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -5378,7 +5420,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5409,7 +5451,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -5467,7 +5509,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5509,7 +5551,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5537,7 +5579,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -5578,7 +5620,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -5601,7 +5643,7 @@ Object { "type": 2, }, "seed": 2019559783, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -5692,7 +5734,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5723,7 +5765,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -5781,7 +5823,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5823,7 +5865,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -5851,7 +5893,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -5892,7 +5934,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -5915,7 +5957,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -5984,7 +6026,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -6031,7 +6073,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6089,7 +6131,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6130,7 +6172,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -6217,7 +6259,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -6275,7 +6317,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -6316,7 +6358,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -6403,7 +6445,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6436,7 +6478,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6469,7 +6511,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6527,7 +6569,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6569,7 +6611,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6597,7 +6639,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6639,7 +6681,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6667,7 +6709,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6695,7 +6737,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6743,7 +6785,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6773,7 +6815,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6803,7 +6845,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6844,7 +6886,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -6936,7 +6978,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -6967,7 +7009,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -7025,7 +7067,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -7067,7 +7109,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -7095,7 +7137,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -7140,7 +7182,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -7168,7 +7210,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -7209,7 +7251,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -7294,7 +7336,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -7325,7 +7367,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -7356,7 +7398,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -7402,7 +7444,7 @@ Object { "seed": 1150084233, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -7448,7 +7490,7 @@ Object { "seed": 238820263, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -7501,7 +7543,7 @@ Object { "seed": 1505387817, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -7554,7 +7596,7 @@ Object { "seed": 760410951, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -7607,7 +7649,7 @@ Object { "roundness": null, "seed": 941653321, "simulatePressure": false, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "freedraw", @@ -7665,7 +7707,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -7707,7 +7749,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -7735,7 +7777,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -7777,7 +7819,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -7805,7 +7847,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -7833,7 +7875,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -7875,7 +7917,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -7903,7 +7945,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -7931,7 +7973,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -7974,7 +8016,7 @@ Object { "seed": 1150084233, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -8016,7 +8058,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -8044,7 +8086,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -8072,7 +8114,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -8115,7 +8157,7 @@ Object { "seed": 1150084233, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -8158,7 +8200,7 @@ Object { "seed": 238820263, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -8200,7 +8242,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -8228,7 +8270,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -8256,7 +8298,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -8299,7 +8341,7 @@ Object { "seed": 1150084233, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -8342,7 +8384,7 @@ Object { "seed": 238820263, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -8388,7 +8430,7 @@ Object { "seed": 1505387817, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -8430,7 +8472,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -8458,7 +8500,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -8486,7 +8528,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -8529,7 +8571,7 @@ Object { "seed": 1150084233, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -8572,7 +8614,7 @@ Object { "seed": 238820263, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -8622,7 +8664,7 @@ Object { "seed": 1505387817, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -8664,7 +8706,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -8692,7 +8734,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -8720,7 +8762,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -8763,7 +8805,7 @@ Object { "seed": 1150084233, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -8806,7 +8848,7 @@ Object { "seed": 238820263, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -8856,7 +8898,7 @@ Object { "seed": 1505387817, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -8902,7 +8944,7 @@ Object { "seed": 760410951, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -8944,7 +8986,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -8972,7 +9014,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -9000,7 +9042,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -9043,7 +9085,7 @@ Object { "seed": 1150084233, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -9086,7 +9128,7 @@ Object { "seed": 238820263, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -9136,7 +9178,7 @@ Object { "seed": 1505387817, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -9186,7 +9228,7 @@ Object { "seed": 760410951, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -9228,7 +9270,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -9256,7 +9298,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -9284,7 +9326,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -9327,7 +9369,7 @@ Object { "seed": 1150084233, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -9370,7 +9412,7 @@ Object { "seed": 238820263, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -9420,7 +9462,7 @@ Object { "seed": 1505387817, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -9470,7 +9512,7 @@ Object { "seed": 760410951, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -9520,7 +9562,7 @@ Object { "roundness": null, "seed": 941653321, "simulatePressure": false, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "freedraw", @@ -9561,7 +9603,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -9651,7 +9693,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -9682,7 +9724,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -9713,7 +9755,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -9771,7 +9813,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -9813,7 +9855,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -9841,7 +9883,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -9883,7 +9925,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -9911,7 +9953,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -9939,7 +9981,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -9971,7 +10013,7 @@ Object { "collaborators": Map {}, "contextMenu": null, "currentChartType": "bar", - "currentItemBackgroundColor": "#fa5252", + "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -9980,7 +10022,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -10009,7 +10051,7 @@ Object { "offsetTop": 0, "openDialog": null, "openMenu": null, - "openPopup": null, + "openPopup": "elementBackground", "openSidebar": null, "pasteDialog": Object { "data": null, @@ -10056,11 +10098,11 @@ Object { exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] element 0 1`] = ` Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 0, + "height": 1000, "id": "id0", "isDeleted": false, "link": null, @@ -10071,14 +10113,14 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", "updated": 1, - "version": 1, - "versionNonce": 0, - "width": 0, + "version": 2, + "versionNonce": 1278240551, + "width": 1000, "x": 0, "y": 0, } @@ -10087,7 +10129,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 partially overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] element 1 1`] = ` Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10101,14 +10143,14 @@ Object { "roundness": Object { "type": 2, }, - "seed": 1278240551, - "strokeColor": "#000000", + "seed": 449462985, + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", "updated": 1, "version": 2, - "versionNonce": 449462985, + "versionNonce": 453191, "width": 1000, "x": 500, "y": 500, @@ -10136,18 +10178,20 @@ Object { "editingGroupId": null, "editingLinearElement": null, "name": "Untitled-201933152653", - "selectedElementIds": Object {}, + "selectedElementIds": Object { + "id0": true, + }, "selectedGroupIds": Object {}, "viewBackgroundColor": "#ffffff", }, "elements": Array [ Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 0, + "height": 1000, "id": "id0", "isDeleted": false, "link": null, @@ -10158,14 +10202,14 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", "updated": 1, - "version": 1, - "versionNonce": 0, - "width": 0, + "version": 2, + "versionNonce": 1278240551, + "width": 1000, "x": 0, "y": 0, }, @@ -10185,11 +10229,11 @@ Object { "elements": Array [ Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 0, + "height": 1000, "id": "id0", "isDeleted": false, "link": null, @@ -10200,20 +10244,20 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", "updated": 1, - "version": 1, - "versionNonce": 0, - "width": 0, + "version": 2, + "versionNonce": 1278240551, + "width": 1000, "x": 0, "y": 0, }, Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10227,14 +10271,14 @@ Object { "roundness": Object { "type": 2, }, - "seed": 1278240551, - "strokeColor": "#000000", + "seed": 449462985, + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", "updated": 1, "version": 2, - "versionNonce": 449462985, + "versionNonce": 453191, "width": 1000, "x": 500, "y": 500, @@ -10269,7 +10313,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -10358,7 +10402,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10389,7 +10433,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10448,7 +10492,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10476,7 +10520,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10517,7 +10561,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -10607,7 +10651,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10638,7 +10682,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10697,7 +10741,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10725,7 +10769,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10769,7 +10813,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10797,7 +10841,7 @@ Object { "type": 3, }, "seed": 1278240551, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10838,7 +10882,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -10923,7 +10967,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -10981,7 +11025,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -11022,7 +11066,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -11107,7 +11151,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -11165,7 +11209,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -11206,7 +11250,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -11291,7 +11335,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -11349,7 +11393,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -11390,7 +11434,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -11513,7 +11557,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -11586,7 +11630,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -11627,7 +11671,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -11750,7 +11794,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -11823,7 +11867,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -11864,7 +11908,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -11971,7 +12015,7 @@ Object { "roundness": null, "seed": 337897, "simulatePressure": false, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "freedraw", @@ -12051,7 +12095,7 @@ Object { "roundness": null, "seed": 337897, "simulatePressure": false, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "freedraw", @@ -12092,7 +12136,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -12215,7 +12259,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -12288,7 +12332,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -12329,7 +12373,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -12414,7 +12458,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -12472,7 +12516,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -12513,7 +12557,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -12636,7 +12680,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -12709,7 +12753,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -12750,7 +12794,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -12835,7 +12879,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -12893,7 +12937,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -12934,7 +12978,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -13041,7 +13085,7 @@ Object { "roundness": null, "seed": 337897, "simulatePressure": false, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "freedraw", @@ -13121,7 +13165,7 @@ Object { "roundness": null, "seed": 337897, "simulatePressure": false, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "freedraw", @@ -13162,7 +13206,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -13247,7 +13291,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13305,7 +13349,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13346,7 +13390,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -13444,7 +13488,7 @@ Object { "type": 3, }, "seed": 915032327, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13477,7 +13521,7 @@ Object { "type": 3, }, "seed": 747212839, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13510,7 +13554,7 @@ Object { "type": 3, }, "seed": 760410951, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13543,7 +13587,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13576,7 +13620,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13609,7 +13653,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13667,7 +13711,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13709,7 +13753,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13737,7 +13781,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13779,7 +13823,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13807,7 +13851,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13835,7 +13879,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13884,7 +13928,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13914,7 +13958,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13944,7 +13988,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -13994,7 +14038,7 @@ Object { "type": 3, }, "seed": 915032327, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14024,7 +14068,7 @@ Object { "type": 3, }, "seed": 747212839, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14054,7 +14098,7 @@ Object { "type": 3, }, "seed": 760410951, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14084,7 +14128,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14114,7 +14158,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14144,7 +14188,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14185,7 +14229,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -14274,7 +14318,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14305,7 +14349,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14363,7 +14407,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14405,7 +14449,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14433,7 +14477,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14474,7 +14518,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -14585,7 +14629,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -14694,7 +14738,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -14782,7 +14826,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14840,7 +14884,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -14881,7 +14925,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -14975,7 +15019,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15006,7 +15050,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15064,7 +15108,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15106,7 +15150,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15134,7 +15178,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15180,7 +15224,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15208,7 +15252,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15249,7 +15293,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -15340,7 +15384,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15371,7 +15415,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15402,7 +15446,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15460,7 +15504,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15502,7 +15546,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15530,7 +15574,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15572,7 +15616,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15600,7 +15644,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15628,7 +15672,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15677,7 +15721,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15707,7 +15751,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15737,7 +15781,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15783,7 +15827,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15811,7 +15855,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15839,7 +15883,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -15871,7 +15915,7 @@ Object { "collaborators": Map {}, "contextMenu": null, "currentChartType": "bar", - "currentItemBackgroundColor": "#fa5252", + "currentItemBackgroundColor": "#ffc9c9", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -15880,7 +15924,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -15909,7 +15953,7 @@ Object { "offsetTop": 0, "openDialog": null, "openMenu": null, - "openPopup": null, + "openPopup": "elementBackground", "openSidebar": null, "pasteDialog": Object { "data": null, @@ -15925,6 +15969,7 @@ Object { "scrolledOutside": false, "selectedElementIds": Object { "id0": true, + "id1": true, }, "selectedGroupIds": Object {}, "selectedLinearElement": null, @@ -15950,7 +15995,7 @@ Object { exports[`regression tests should show fill icons when element has non transparent background: [end of test] element 0 1`] = ` Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], @@ -15965,7 +16010,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16023,7 +16068,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16050,7 +16095,7 @@ Object { "elements": Array [ Object { "angle": 0, - "backgroundColor": "#fa5252", + "backgroundColor": "#ffc9c9", "boundElements": null, "fillStyle": "hachure", "groupIds": Array [], @@ -16065,7 +16110,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16084,7 +16129,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`] = `14`; +exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of renders 1`] = `13`; exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] appState 1`] = ` Object { @@ -16106,7 +16151,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -16205,7 +16250,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16239,7 +16284,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16273,7 +16318,7 @@ Object { "type": 3, }, "seed": 1014066025, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16307,7 +16352,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16365,7 +16410,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16407,7 +16452,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16435,7 +16480,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16484,7 +16529,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16514,7 +16559,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16558,7 +16603,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16588,7 +16633,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16616,7 +16661,7 @@ Object { "type": 3, }, "seed": 1014066025, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16660,7 +16705,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16690,7 +16735,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16718,7 +16763,7 @@ Object { "type": 3, }, "seed": 1014066025, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16746,7 +16791,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16795,7 +16840,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16825,7 +16870,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16855,7 +16900,7 @@ Object { "type": 3, }, "seed": 1014066025, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16885,7 +16930,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16935,7 +16980,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16966,7 +17011,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -16997,7 +17042,7 @@ Object { "type": 3, }, "seed": 1014066025, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17028,7 +17073,7 @@ Object { "type": 3, }, "seed": 400692809, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17069,7 +17114,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -17178,7 +17223,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -17267,7 +17312,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17301,7 +17346,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17335,7 +17380,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17393,7 +17438,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17435,7 +17480,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17463,7 +17508,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17505,7 +17550,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17533,7 +17578,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17561,7 +17606,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17609,7 +17654,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17639,7 +17684,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17669,7 +17714,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17715,7 +17760,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17745,7 +17790,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17775,7 +17820,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17823,7 +17868,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17854,7 +17899,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17885,7 +17930,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17934,7 +17979,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17965,7 +18010,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -17996,7 +18041,7 @@ Object { "type": 3, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -18037,7 +18082,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -18060,7 +18105,7 @@ Object { "type": 2, }, "seed": 1116226695, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -18133,7 +18178,7 @@ Object { "type": 2, }, "seed": 1116226695, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -18180,7 +18225,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -18211,7 +18256,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -18242,7 +18287,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -18300,7 +18345,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -18342,7 +18387,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -18370,7 +18415,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -18412,7 +18457,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -18440,7 +18485,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -18468,7 +18513,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -18509,7 +18554,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -18532,7 +18577,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -18603,7 +18648,7 @@ Object { "type": 2, }, "seed": 401146281, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "selection", @@ -18650,7 +18695,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -18681,7 +18726,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -18739,7 +18784,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -18781,7 +18826,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -18809,7 +18854,7 @@ Object { "type": 2, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -18850,7 +18895,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -18961,7 +19006,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -19046,7 +19091,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19077,7 +19122,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19126,7 +19171,7 @@ Object { "seed": 401146281, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -19172,7 +19217,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19200,7 +19245,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19250,7 +19295,7 @@ Object { "seed": 401146281, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -19292,7 +19337,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19320,7 +19365,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19366,7 +19411,7 @@ Object { "seed": 401146281, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -19421,7 +19466,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19463,7 +19508,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19491,7 +19536,7 @@ Object { "type": 3, }, "seed": 449462985, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", @@ -19532,7 +19577,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", @@ -19641,7 +19686,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", diff --git a/src/tests/__snapshots__/selection.test.tsx.snap b/src/tests/__snapshots__/selection.test.tsx.snap index 6379fa0aa..61c4dc97a 100644 --- a/src/tests/__snapshots__/selection.test.tsx.snap +++ b/src/tests/__snapshots__/selection.test.tsx.snap @@ -33,7 +33,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -79,7 +79,7 @@ Object { "seed": 337897, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -110,7 +110,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "diamond", @@ -141,7 +141,7 @@ Object { "type": 2, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "ellipse", @@ -172,7 +172,7 @@ Object { "type": 3, }, "seed": 337897, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", diff --git a/src/tests/contextmenu.test.tsx b/src/tests/contextmenu.test.tsx index 0a74de367..9b4007b03 100644 --- a/src/tests/contextmenu.test.tsx +++ b/src/tests/contextmenu.test.tsx @@ -9,6 +9,7 @@ import { queryByText, queryAllByText, waitFor, + togglePopover, } from "./test-utils"; import ExcalidrawApp from "../excalidraw-app"; import * as Renderer from "../renderer/renderScene"; @@ -19,7 +20,6 @@ import { ShortcutName } from "../actions/shortcuts"; import { copiedStyles } from "../actions/actionStyles"; import { API } from "./helpers/api"; import { setDateTimeForTests } from "../utils"; -import { t } from "../i18n"; import { LibraryItem } from "../types"; const checkpoint = (name: string) => { @@ -303,10 +303,10 @@ describe("contextMenu element", () => { mouse.up(20, 20); // Change some styles of second rectangle - UI.clickLabeledElement("Stroke"); - UI.clickLabeledElement(t("colors.c92a2a")); - UI.clickLabeledElement("Background"); - UI.clickLabeledElement(t("colors.e64980")); + togglePopover("Stroke"); + UI.clickOnTestId("color-red"); + togglePopover("Background"); + UI.clickOnTestId("color-blue"); // Fill style fireEvent.click(screen.getByTitle("Cross-hatch")); // Stroke width @@ -320,13 +320,20 @@ describe("contextMenu element", () => { target: { value: "60" }, }); + // closing the background popover as this blocks + // context menu from rendering after we started focussing + // the popover once rendered :/ + togglePopover("Background"); + mouse.reset(); + // Copy styles of second rectangle fireEvent.contextMenu(GlobalTestState.canvas, { button: 2, clientX: 40, clientY: 40, }); + let contextMenu = UI.queryContextMenu(); fireEvent.click(queryByText(contextMenu!, "Copy styles")!); const secondRect = JSON.parse(copiedStyles)[0]; @@ -344,8 +351,8 @@ describe("contextMenu element", () => { const firstRect = API.getSelectedElement(); expect(firstRect.id).toBe(h.elements[0].id); - expect(firstRect.strokeColor).toBe("#c92a2a"); - expect(firstRect.backgroundColor).toBe("#e64980"); + expect(firstRect.strokeColor).toBe("#e03131"); + expect(firstRect.backgroundColor).toBe("#a5d8ff"); expect(firstRect.fillStyle).toBe("cross-hatch"); expect(firstRect.strokeWidth).toBe(2); // Bold: 2 expect(firstRect.strokeStyle).toBe("dotted"); diff --git a/src/tests/data/__snapshots__/restore.test.ts.snap b/src/tests/data/__snapshots__/restore.test.ts.snap index 7e30b9d86..cfb57ecb2 100644 --- a/src/tests/data/__snapshots__/restore.test.ts.snap +++ b/src/tests/data/__snapshots__/restore.test.ts.snap @@ -33,7 +33,7 @@ Object { "seed": Any, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "arrow", @@ -173,7 +173,7 @@ Object { }, "seed": Any, "simulatePressure": true, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "freedraw", @@ -219,7 +219,7 @@ Object { "seed": Any, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -265,7 +265,7 @@ Object { "seed": Any, "startArrowhead": null, "startBinding": null, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "type": "line", @@ -302,7 +302,7 @@ Object { "type": 3, }, "seed": Any, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "text": "text", @@ -342,7 +342,7 @@ Object { "type": 3, }, "seed": Any, - "strokeColor": "#000000", + "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 1, "text": "", diff --git a/src/tests/helpers/ui.ts b/src/tests/helpers/ui.ts index fcf67166b..c88201133 100644 --- a/src/tests/helpers/ui.ts +++ b/src/tests/helpers/ui.ts @@ -237,6 +237,15 @@ export class UI { fireEvent.click(element); }; + static clickOnTestId = (testId: string) => { + const element = document.querySelector(`[data-testid='${testId}']`); + // const element = GlobalTestState.renderResult.queryByTestId(testId); + if (!element) { + throw new Error(`No element with testid "${testId}" found`); + } + fireEvent.click(element); + }; + /** * Creates an Excalidraw element, and returns a proxy that wraps it so that * accessing props will return the latest ones from the object existing in diff --git a/src/tests/packages/__snapshots__/excalidraw.test.tsx.snap b/src/tests/packages/__snapshots__/excalidraw.test.tsx.snap index d703dff87..4caa6c6dd 100644 --- a/src/tests/packages/__snapshots__/excalidraw.test.tsx.snap +++ b/src/tests/packages/__snapshots__/excalidraw.test.tsx.snap @@ -7,7 +7,7 @@ exports[` should render main menu with host menu items > - + + + + +
+
+
diff --git a/src/tests/packages/__snapshots__/utils.test.ts.snap b/src/tests/packages/__snapshots__/utils.test.ts.snap index aa5f84334..98303fb75 100644 --- a/src/tests/packages/__snapshots__/utils.test.ts.snap +++ b/src/tests/packages/__snapshots__/utils.test.ts.snap @@ -20,7 +20,7 @@ Object { "currentItemRoughness": 1, "currentItemRoundness": "round", "currentItemStartArrowhead": null, - "currentItemStrokeColor": "#000000", + "currentItemStrokeColor": "#1e1e1e", "currentItemStrokeStyle": "solid", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", diff --git a/src/tests/regressionTests.test.tsx b/src/tests/regressionTests.test.tsx index 07a6a449f..9ecbfb42c 100644 --- a/src/tests/regressionTests.test.tsx +++ b/src/tests/regressionTests.test.tsx @@ -12,11 +12,11 @@ import { fireEvent, render, screen, + togglePopover, waitFor, } from "./test-utils"; import { defaultLang } from "../i18n"; import { FONT_FAMILY } from "../constants"; -import { t } from "../i18n"; const { h } = window; @@ -42,7 +42,6 @@ const checkpoint = (name: string) => { expect(element).toMatchSnapshot(`[${name}] element ${i}`), ); }; - beforeEach(async () => { // Unmount ReactDOM from root ReactDOM.unmountComponentAtNode(document.getElementById("root")!); @@ -159,13 +158,14 @@ describe("regression tests", () => { UI.clickTool("rectangle"); mouse.down(10, 10); mouse.up(10, 10); + togglePopover("Background"); + UI.clickOnTestId("color-yellow"); + UI.clickOnTestId("color-red"); - UI.clickLabeledElement("Background"); - UI.clickLabeledElement(t("colors.fa5252")); - UI.clickLabeledElement("Stroke"); - UI.clickLabeledElement(t("colors.5f3dc4")); - expect(API.getSelectedElement().backgroundColor).toBe("#fa5252"); - expect(API.getSelectedElement().strokeColor).toBe("#5f3dc4"); + togglePopover("Stroke"); + UI.clickOnTestId("color-blue"); + expect(API.getSelectedElement().backgroundColor).toBe("#ffc9c9"); + expect(API.getSelectedElement().strokeColor).toBe("#1971c2"); }); it("click on an element and drag it", () => { @@ -988,8 +988,8 @@ describe("regression tests", () => { UI.clickTool("rectangle"); // change background color since default is transparent // and transparent elements can't be selected by clicking inside of them - UI.clickLabeledElement("Background"); - UI.clickLabeledElement(t("colors.fa5252")); + togglePopover("Background"); + UI.clickOnTestId("color-red"); mouse.down(); mouse.up(1000, 1000); @@ -1088,15 +1088,14 @@ describe("regression tests", () => { assertSelectedElements(rect3); }); - it("should show fill icons when element has non transparent background", () => { + it("should show fill icons when element has non transparent background", async () => { UI.clickTool("rectangle"); expect(screen.queryByText(/fill/i)).not.toBeNull(); mouse.down(); mouse.up(10, 10); expect(screen.queryByText(/fill/i)).toBeNull(); - - UI.clickLabeledElement("Background"); - UI.clickLabeledElement(t("colors.fa5252")); + togglePopover("Background"); + UI.clickOnTestId("color-red"); // select rectangle mouse.reset(); mouse.click(); diff --git a/src/tests/test-utils.ts b/src/tests/test-utils.ts index 9560f681f..bb771b196 100644 --- a/src/tests/test-utils.ts +++ b/src/tests/test-utils.ts @@ -16,6 +16,7 @@ import { STORAGE_KEYS } from "../excalidraw-app/app_constants"; import { SceneData } from "../types"; import { getSelectedElements } from "../scene/selection"; import { ExcalidrawElement } from "../element/types"; +import { UI } from "./helpers/ui"; const customQueries = { ...queries, @@ -186,11 +187,6 @@ export const assertSelectedElements = ( expect(selectedElementIds).toEqual(expect.arrayContaining(ids)); }; -export const toggleMenu = (container: HTMLElement) => { - // open menu - fireEvent.click(container.querySelector(".dropdown-menu-button")!); -}; - export const createPasteEvent = ( text: | string @@ -211,3 +207,24 @@ export const createPasteEvent = ( }, ); }; + +export const toggleMenu = (container: HTMLElement) => { + // open menu + fireEvent.click(container.querySelector(".dropdown-menu-button")!); +}; + +export const togglePopover = (label: string) => { + // Needed for radix-ui/react-popover as tests fail due to resize observer not being present + (global as any).ResizeObserver = class ResizeObserver { + constructor(cb: any) { + (this as any).cb = cb; + } + + observe() {} + + unobserve() {} + disconnect() {} + }; + + UI.clickLabeledElement(label); +}; diff --git a/src/types.ts b/src/types.ts index 666f9e03b..52a75b615 100644 --- a/src/types.ts +++ b/src/types.ts @@ -163,11 +163,7 @@ export type AppState = { isRotating: boolean; zoom: Zoom; openMenu: "canvas" | "shape" | null; - openPopup: - | "canvasColorPicker" - | "backgroundColorPicker" - | "strokeColorPicker" - | null; + openPopup: "canvasBackground" | "elementBackground" | "elementStroke" | null; openSidebar: { name: SidebarName; tab?: SidebarTabName } | null; openDialog: "imageExport" | "help" | "jsonExport" | null; /** @@ -542,4 +538,5 @@ export type Device = Readonly<{ isMobile: boolean; isTouchScreen: boolean; canDeviceFitSidebar: boolean; + isLandscape: boolean; }>; diff --git a/src/utils.ts b/src/utils.ts index 83376cd3b..b5a65cae2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,5 @@ import oc from "open-color"; - -import colors from "./colors"; +import { COLOR_PALETTE } from "./colors"; import { CURSOR_TYPE, DEFAULT_VERSION, @@ -529,7 +528,7 @@ export const isTransparent = (color: string) => { return ( isRGBTransparent || isRRGGBBTransparent || - color === colors.elementBackground[0] + color === COLOR_PALETTE.transparent ); }; diff --git a/yarn.lock b/yarn.lock index b4cc8c6f8..eca6964bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,12 +2,12 @@ # yarn lockfile v1 -"@ampproject/remapping@^2.1.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== dependencies: - "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" "@apideck/better-ajv-errors@^0.3.1": @@ -26,90 +26,56 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.8.3": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.21.4", "@babel/code-frame@^7.8.3": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" + integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== dependencies: "@babel/highlight" "^7.18.6" -"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.19.4", "@babel/compat-data@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.0.tgz#9b61938c5f688212c7b9ae363a819df7d29d4093" - integrity sha512-Gt9jszFJYq7qzXVK4slhc6NzJXnOVmRECWcVjF/T23rNXD9NtWQ0W3qxdg+p9wWIB+VQw3GYV/U2Ha9bRTfs4w== +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.4.tgz#457ffe647c480dff59c2be092fc3acf71195c87f" + integrity sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g== -"@babel/compat-data@^7.20.1": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30" - integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ== - -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.16.0": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.6.tgz#7122ae4f5c5a37c0946c066149abd8e75f81540f" - integrity sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg== +"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.4.tgz#c6dc73242507b8e2a27fd13a9c1814f9fa34a659" + integrity sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA== dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.19.6" - "@babel/helper-compilation-targets" "^7.19.3" - "@babel/helper-module-transforms" "^7.19.6" - "@babel/helpers" "^7.19.4" - "@babel/parser" "^7.19.6" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.6" - "@babel/types" "^7.19.4" + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.4" + "@babel/helper-compilation-targets" "^7.21.4" + "@babel/helper-module-transforms" "^7.21.2" + "@babel/helpers" "^7.21.0" + "@babel/parser" "^7.21.4" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.4" + "@babel/types" "^7.21.4" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" - json5 "^2.2.1" - semver "^6.3.0" - -"@babel/core@^7.11.1", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.2.tgz#8dc9b1620a673f92d3624bd926dc49a52cf25b92" - integrity sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.20.2" - "@babel/helper-compilation-targets" "^7.20.0" - "@babel/helper-module-transforms" "^7.20.2" - "@babel/helpers" "^7.20.1" - "@babel/parser" "^7.20.2" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.20.1" - "@babel/types" "^7.20.2" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.1" + json5 "^2.2.2" semver "^6.3.0" "@babel/eslint-parser@^7.16.3": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz#4f68f6b0825489e00a24b41b6a1ae35414ecd2f4" - integrity sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ== + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz#d79e822050f2de65d7f368a076846e7184234af7" + integrity sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg== dependencies: "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.19.6", "@babel/generator@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.0.tgz#0bfc5379e0efb05ca6092091261fcdf7ec36249d" - integrity sha512-GUPcXxWibClgmYJuIwC2Bc2Lg+8b9VjaJ+HlNdACEVt+Wlr1eoU1OPZjZRm7Hzl0gaTsUZNQfeihvZJhG7oc3w== +"@babel/generator@^7.21.4", "@babel/generator@^7.7.2": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.4.tgz#64a94b7448989f421f919d5239ef553b37bb26bc" + integrity sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA== dependencies: - "@babel/types" "^7.20.0" - "@jridgewell/gen-mapping" "^0.3.2" - jsesc "^2.5.1" - -"@babel/generator@^7.20.1", "@babel/generator@^7.20.2", "@babel/generator@^7.7.2": - version "7.20.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.4.tgz#4d9f8f0c30be75fd90a0562099a26e5839602ab8" - integrity sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA== - dependencies: - "@babel/types" "^7.20.2" + "@babel/types" "^7.21.4" "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" "@babel/helper-annotate-as-pure@^7.18.6": @@ -127,36 +93,38 @@ "@babel/helper-explode-assignable-expression" "^7.18.6" "@babel/types" "^7.18.9" -"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.19.0", "@babel/helper-compilation-targets@^7.19.3", "@babel/helper-compilation-targets@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz#6bf5374d424e1b3922822f1d9bdaa43b1a139d0a" - integrity sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ== +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz#770cd1ce0889097ceacb99418ee6934ef0572656" + integrity sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg== dependencies: - "@babel/compat-data" "^7.20.0" - "@babel/helper-validator-option" "^7.18.6" + "@babel/compat-data" "^7.21.4" + "@babel/helper-validator-option" "^7.21.0" browserslist "^4.21.3" + lru-cache "^5.1.1" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz#bfd6904620df4e46470bae4850d66be1054c404b" - integrity sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw== +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz#3a017163dc3c2ba7deb9a7950849a9586ea24c18" + integrity sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" - "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-member-expression-to-functions" "^7.21.0" "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" "@babel/helper-split-export-declaration" "^7.18.6" -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz#7976aca61c0984202baca73d84e2337a5424a41b" - integrity sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw== +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.4.tgz#40411a8ab134258ad2cf3a3d987ec6aa0723cee5" + integrity sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" - regexpu-core "^5.1.0" + regexpu-core "^5.3.1" "@babel/helper-define-polyfill-provider@^0.3.3": version "0.3.3" @@ -182,13 +150,13 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" - integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== +"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" + integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== dependencies: - "@babel/template" "^7.18.10" - "@babel/types" "^7.19.0" + "@babel/template" "^7.20.7" + "@babel/types" "^7.21.0" "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" @@ -197,47 +165,33 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-member-expression-to-functions@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815" - integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg== +"@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz#319c6a940431a133897148515877d2f3269c3ba5" + integrity sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q== dependencies: - "@babel/types" "^7.18.9" + "@babel/types" "^7.21.0" -"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== +"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af" + integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg== dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.21.4" -"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz#6c52cc3ac63b70952d33ee987cbee1c9368b533f" - integrity sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.19.4" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.6" - "@babel/types" "^7.19.4" - -"@babel/helper-module-transforms@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz#ac53da669501edd37e658602a21ba14c08748712" - integrity sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA== +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.2": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" + integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== dependencies: "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-module-imports" "^7.18.6" "@babel/helper-simple-access" "^7.20.2" "@babel/helper-split-export-declaration" "^7.18.6" "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.20.1" - "@babel/types" "^7.20.2" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.2" + "@babel/types" "^7.21.2" "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" @@ -246,17 +200,12 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf" - integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw== - -"@babel/helper-plugin-utils@^7.20.2": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.20.2" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== -"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": +"@babel/helper-remap-async-to-generator@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== @@ -266,23 +215,17 @@ "@babel/helper-wrap-function" "^7.18.9" "@babel/types" "^7.18.9" -"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9", "@babel/helper-replace-supers@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz#e1592a9b4b368aa6bdb8784a711e0bcbf0612b78" - integrity sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw== +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz#243ecd2724d2071532b2c8ad2f0f9f083bcae331" + integrity sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A== dependencies: "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.20.7" "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/traverse" "^7.19.1" - "@babel/types" "^7.19.0" - -"@babel/helper-simple-access@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz#be553f4951ac6352df2567f7daa19a0ee15668e7" - integrity sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg== - dependencies: - "@babel/types" "^7.19.4" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.7" + "@babel/types" "^7.20.7" "@babel/helper-simple-access@^7.20.2": version "7.20.2" @@ -291,7 +234,7 @@ dependencies: "@babel/types" "^7.20.2" -"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": +"@babel/helper-skip-transparent-expression-wrappers@^7.20.0": version "7.20.0" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== @@ -315,38 +258,29 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== -"@babel/helper-validator-option@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" - integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== +"@babel/helper-validator-option@^7.18.6", "@babel/helper-validator-option@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" + integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== "@babel/helper-wrap-function@^7.18.9": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz#89f18335cff1152373222f76a4b37799636ae8b1" - integrity sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg== + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" + integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== dependencies: "@babel/helper-function-name" "^7.19.0" "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.0" - "@babel/types" "^7.19.0" + "@babel/traverse" "^7.20.5" + "@babel/types" "^7.20.5" -"@babel/helpers@^7.19.4": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.0.tgz#27c8ffa8cc32a2ed3762fba48886e7654dbcf77f" - integrity sha512-aGMjYraN0zosCEthoGLdqot1oRsmxVTQRHadsUPz5QM44Zej2PYRz7XiDE7GqnkZnNtLbOuxqoZw42vkU7+XEQ== +"@babel/helpers@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" + integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== dependencies: - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.20.0" - "@babel/types" "^7.20.0" - -"@babel/helpers@^7.20.1": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.1.tgz#2ab7a0fcb0a03b5bf76629196ed63c2d7311f4c9" - integrity sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg== - dependencies: - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.20.1" - "@babel/types" "^7.20.0" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.0" + "@babel/types" "^7.21.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6": version "7.18.6" @@ -357,15 +291,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.19.6", "@babel/parser@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.0.tgz#b26133c888da4d79b0d3edcf42677bcadc783046" - integrity sha512-G9VgAhEaICnz8iiJeGJQyVl6J2nTjbW0xeisva0PK6XcKsga7BIaqm4ZF8Rg1Wbaqmy6znspNqhPaPkyukujzg== - -"@babel/parser@^7.20.1", "@babel/parser@^7.20.2": - version "7.20.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2" - integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17" + integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" @@ -374,32 +303,22 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz#a11af19aa373d68d561f08e0a57242350ed0ec50" - integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz#d9c85589258539a22a901033853101a6198d4ef1" + integrity sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" - "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/plugin-proposal-optional-chaining" "^7.20.7" -"@babel/plugin-proposal-async-generator-functions@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz#34f6f5174b688529342288cd264f80c9ea9fb4a7" - integrity sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q== +"@babel/plugin-proposal-async-generator-functions@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" + integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== dependencies: "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-remap-async-to-generator" "^7.18.9" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-async-generator-functions@^7.20.1": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz#352f02baa5d69f4e7529bdac39aaa02d41146af9" - integrity sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/helper-remap-async-to-generator" "^7.18.9" "@babel/plugin-syntax-async-generators" "^7.8.4" @@ -411,25 +330,25 @@ "@babel/helper-create-class-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-proposal-class-static-block@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz#8aa81d403ab72d3962fc06c26e222dacfc9b9020" - integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw== +"@babel/plugin-proposal-class-static-block@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz#77bdd66fb7b605f3a61302d224bdfacf5547977d" + integrity sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.21.0" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-proposal-decorators@^7.16.4": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.0.tgz#3acef1f1206d7a6a1436aa6ccf9ed7b1bd06aff7" - integrity sha512-vnuRRS20ygSxclEYikHzVrP9nZDFXaSzvJxGLQNAiBX041TmhS4hOUHWNIpq/q4muENuEP9XPJFXTNFejhemkg== + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.21.0.tgz#70e0c89fdcd7465c97593edb8f628ba6e4199d63" + integrity sha512-MfgX49uRrFUTL/HvWtmx3zmpyzMMr4MTj3d527MLlr/4RTT9G/ytFFP7qet2uM2Ve03b+BkpWUpK+lRXnQ+v9w== dependencies: - "@babel/helper-create-class-features-plugin" "^7.19.0" - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-replace-supers" "^7.19.1" + "@babel/helper-create-class-features-plugin" "^7.21.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.20.7" "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/plugin-syntax-decorators" "^7.19.0" + "@babel/plugin-syntax-decorators" "^7.21.0" "@babel/plugin-proposal-dynamic-import@^7.18.6": version "7.18.6" @@ -455,12 +374,12 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz#8148cbb350483bf6220af06fa6db3690e14b2e23" - integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q== +"@babel/plugin-proposal-logical-assignment-operators@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz#dfbcaa8f7b4d37b51e8bfb46d94a5aea2bb89d83" + integrity sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": @@ -479,27 +398,16 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz#a8fc86e8180ff57290c91a75d83fe658189b642d" - integrity sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q== +"@babel/plugin-proposal-object-rest-spread@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" + integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== dependencies: - "@babel/compat-data" "^7.19.4" - "@babel/helper-compilation-targets" "^7.19.3" - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.18.8" - -"@babel/plugin-proposal-object-rest-spread@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz#a556f59d555f06961df1e572bb5eca864c84022d" - integrity sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ== - dependencies: - "@babel/compat-data" "^7.20.1" - "@babel/helper-compilation-targets" "^7.20.0" + "@babel/compat-data" "^7.20.5" + "@babel/helper-compilation-targets" "^7.20.7" "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.1" + "@babel/plugin-transform-parameters" "^7.20.7" "@babel/plugin-proposal-optional-catch-binding@^7.18.6": version "7.18.6" @@ -509,13 +417,13 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.16.0", "@babel/plugin-proposal-optional-chaining@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993" - integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w== +"@babel/plugin-proposal-optional-chaining@^7.16.0", "@babel/plugin-proposal-optional-chaining@^7.20.7", "@babel/plugin-proposal-optional-chaining@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" + integrity sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-proposal-private-methods@^7.16.0", "@babel/plugin-proposal-private-methods@^7.18.6": @@ -526,14 +434,14 @@ "@babel/helper-create-class-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-proposal-private-property-in-object@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz#a64137b232f0aca3733a67eb1a144c192389c503" - integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw== +"@babel/plugin-proposal-private-property-in-object@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz#19496bd9883dd83c23c7d7fc45dcd9ad02dfa1dc" + integrity sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.21.0" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": @@ -572,12 +480,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-decorators@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz#5f13d1d8fce96951bea01a10424463c9a5b3a599" - integrity sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ== +"@babel/plugin-syntax-decorators@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.21.0.tgz#d2b3f31c3e86fa86e16bb540b7660c55bd7d0e78" + integrity sha512-tIoPpGBR8UuM4++ccWN3gifhVvQu7ZizuR1fklhRJrd5ewgbkUS+0KVFeWWxELtn18NTLoW32XV7zyOgIAiz+w== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" @@ -594,13 +502,13 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-flow@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz#774d825256f2379d06139be0c723c4dd444f3ca1" - integrity sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A== + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.21.4.tgz#3e37fca4f06d93567c1cd9b75156422e90a67107" + integrity sha512-l9xd3N+XG4fZRxEP3vXdK6RW7vN1Uf5dxzRC/09wV86wqZ/YYQooBIGNsiRdfNR3/q2/5pPzV4B54J/9ctX5jw== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-syntax-import-assertions@^7.18.6", "@babel/plugin-syntax-import-assertions@^7.20.0": +"@babel/plugin-syntax-import-assertions@^7.20.0": version "7.20.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz#bb50e0d4bea0957235390641209394e87bdb9cc4" integrity sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ== @@ -621,12 +529,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" - integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== +"@babel/plugin-syntax-jsx@^7.18.6", "@babel/plugin-syntax-jsx@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz#f264ed7bf40ffc9ec239edabc17a50c4f5b6fea2" + integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" @@ -685,27 +593,27 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.20.0", "@babel/plugin-syntax-typescript@^7.7.2": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7" - integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz#2751948e9b7c6d771a8efa59340c15d4a2891ff8" + integrity sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-arrow-functions@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe" - integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ== +"@babel/plugin-transform-arrow-functions@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz#bea332b0e8b2dab3dafe55a163d8227531ab0551" + integrity sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-async-to-generator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz#ccda3d1ab9d5ced5265fdb13f1882d5476c71615" - integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag== +"@babel/plugin-transform-async-to-generator@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz#dfee18623c8cb31deb796aa3ca84dda9cea94354" + integrity sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q== dependencies: "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-remap-async-to-generator" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-remap-async-to-generator" "^7.18.9" "@babel/plugin-transform-block-scoped-functions@^7.18.6": version "7.18.6" @@ -714,68 +622,40 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-block-scoping@^7.19.4": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.0.tgz#91fe5e6ffc9ba13cb6c95ed7f0b1204f68c988c5" - integrity sha512-sXOohbpHZSk7GjxK9b3dKB7CfqUD5DwOH+DggKzOQ7TXYP+RCSbRykfjQmn/zq+rBjycVRtLf9pYhAaEJA786w== - dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - -"@babel/plugin-transform-block-scoping@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz#f59b1767e6385c663fd0bce655db6ca9c8b236ed" - integrity sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ== +"@babel/plugin-transform-block-scoping@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz#e737b91037e5186ee16b76e7ae093358a5634f02" + integrity sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ== dependencies: "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-classes@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz#0e61ec257fba409c41372175e7c1e606dc79bb20" - integrity sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A== +"@babel/plugin-transform-classes@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz#f469d0b07a4c5a7dbb21afad9e27e57b47031665" + integrity sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-compilation-targets" "^7.19.0" + "@babel/helper-compilation-targets" "^7.20.7" "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-replace-supers" "^7.18.9" - "@babel/helper-split-export-declaration" "^7.18.6" - globals "^11.1.0" - -"@babel/plugin-transform-classes@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz#c0033cf1916ccf78202d04be4281d161f6709bb2" - integrity sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-compilation-targets" "^7.20.0" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" + "@babel/helper-function-name" "^7.21.0" "@babel/helper-optimise-call-expression" "^7.18.6" "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-replace-supers" "^7.19.1" + "@babel/helper-replace-supers" "^7.20.7" "@babel/helper-split-export-declaration" "^7.18.6" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e" - integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw== +"@babel/plugin-transform-computed-properties@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz#704cc2fd155d1c996551db8276d55b9d46e4d0aa" + integrity sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/template" "^7.20.7" -"@babel/plugin-transform-destructuring@^7.19.4": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.0.tgz#712829ef4825d9cc04bb379de316f981e9a6f648" - integrity sha512-1dIhvZfkDVx/zn2S1aFwlruspTt4189j7fEkH0Y0VyuDM6bQt7bD6kLcz3l4IlLG+e5OReaBz9ROAbttRtUHqA== - dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - -"@babel/plugin-transform-destructuring@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz#c23741cfa44ddd35f5e53896e88c75331b8b2792" - integrity sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw== +"@babel/plugin-transform-destructuring@^7.21.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz#73b46d0fd11cd6ef57dea8a381b1215f4959d401" + integrity sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA== dependencies: "@babel/helper-plugin-utils" "^7.20.2" @@ -803,19 +683,19 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-flow-strip-types@^7.16.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz#e9e8606633287488216028719638cbbb2f2dde8f" - integrity sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg== + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz#6aeca0adcb81dc627c8986e770bfaa4d9812aff5" + integrity sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-flow" "^7.18.6" -"@babel/plugin-transform-for-of@^7.18.8": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" - integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== +"@babel/plugin-transform-for-of@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz#964108c9988de1a60b4be2354a7d7e245f36e86e" + integrity sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-transform-function-name@^7.18.9": version "7.18.9" @@ -840,31 +720,31 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-modules-amd@^7.18.6", "@babel/plugin-transform-modules-amd@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz#aca391801ae55d19c4d8d2ebfeaa33df5f2a2cbd" - integrity sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg== +"@babel/plugin-transform-modules-amd@^7.20.11": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz#3daccca8e4cc309f03c3a0c4b41dc4b26f55214a" + integrity sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g== dependencies: - "@babel/helper-module-transforms" "^7.19.6" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-modules-commonjs@^7.18.6", "@babel/plugin-transform-modules-commonjs@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz#25b32feef24df8038fc1ec56038917eacb0b730c" - integrity sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ== +"@babel/plugin-transform-modules-commonjs@^7.21.2": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz#6ff5070e71e3192ef2b7e39820a06fb78e3058e7" + integrity sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA== dependencies: - "@babel/helper-module-transforms" "^7.19.6" - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-simple-access" "^7.19.4" + "@babel/helper-module-transforms" "^7.21.2" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-simple-access" "^7.20.2" -"@babel/plugin-transform-modules-systemjs@^7.19.0", "@babel/plugin-transform-modules-systemjs@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz#59e2a84064b5736a4471b1aa7b13d4431d327e0d" - integrity sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ== +"@babel/plugin-transform-modules-systemjs@^7.20.11": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz#467ec6bba6b6a50634eea61c9c232654d8a4696e" + integrity sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw== dependencies: "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-module-transforms" "^7.19.6" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/helper-validator-identifier" "^7.19.1" "@babel/plugin-transform-modules-umd@^7.18.6": @@ -875,13 +755,13 @@ "@babel/helper-module-transforms" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz#ec7455bab6cd8fb05c525a94876f435a48128888" - integrity sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz#626298dd62ea51d452c3be58b285d23195ba69a8" + integrity sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.19.0" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-create-regexp-features-plugin" "^7.20.5" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-transform-new-target@^7.18.6": version "7.18.6" @@ -898,17 +778,10 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/helper-replace-supers" "^7.18.6" -"@babel/plugin-transform-parameters@^7.18.8": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a" - integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-parameters@^7.20.1": - version "7.20.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.3.tgz#7b3468d70c3c5b62e46be0a47b6045d8590fb748" - integrity sha512-oZg/Fpx0YDrj13KsLyO8I/CX3Zdw7z0O9qOd95SqcoIzuqy/WTGWvePeHAnZCN54SfdyjHcb1S30gc8zlzlHcA== +"@babel/plugin-transform-parameters@^7.20.7", "@babel/plugin-transform-parameters@^7.21.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz#18fc4e797cf6d6d972cb8c411dbe8a809fa157db" + integrity sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ== dependencies: "@babel/helper-plugin-utils" "^7.20.2" @@ -920,11 +793,11 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-react-constant-elements@^7.12.1": - version "7.18.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.18.12.tgz#edf3bec47eb98f14e84fa0af137fcc6aad8e0443" - integrity sha512-Q99U9/ttiu+LMnRU8psd23HhvwXmKWDQIpocm0JKaICcZHnw+mdQbHm6xnSy7dOl8I5PELakYtNBubNQlBXbZw== + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz#b32a5556100d424b25e388dd689050d78396884d" + integrity sha512-4DVcFeWe/yDYBLp0kBmOGFJ6N2UYg7coGid1gdxb4co62dy/xISDMaYBXBVXEDhfgMk7qkbcYiGtwd5Q/hwDDQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-transform-react-display-name@^7.16.0", "@babel/plugin-transform-react-display-name@^7.18.6": version "7.18.6" @@ -941,15 +814,15 @@ "@babel/plugin-transform-react-jsx" "^7.18.6" "@babel/plugin-transform-react-jsx@^7.18.6": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz#b3cbb7c3a00b92ec8ae1027910e331ba5c500eb9" - integrity sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg== + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz#656b42c2fdea0a6d8762075d58ef9d4e3c4ab8a2" + integrity sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-jsx" "^7.18.6" - "@babel/types" "^7.19.0" + "@babel/types" "^7.21.0" "@babel/plugin-transform-react-pure-annotations@^7.18.6": version "7.18.6" @@ -959,13 +832,13 @@ "@babel/helper-annotate-as-pure" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-regenerator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73" - integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ== +"@babel/plugin-transform-regenerator@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d" + integrity sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - regenerator-transform "^0.15.0" + "@babel/helper-plugin-utils" "^7.20.2" + regenerator-transform "^0.15.1" "@babel/plugin-transform-reserved-words@^7.18.6": version "7.18.6" @@ -975,12 +848,12 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-runtime@^7.16.4": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz#9d2a9dbf4e12644d6f46e5e75bfbf02b5d6e9194" - integrity sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw== + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.4.tgz#2e1da21ca597a7d01fc96b699b21d8d2023191aa" + integrity sha512-1J4dhrw1h1PqnNNpzwxQ2UBymJUF8KuPjAAnlLwZcGhHAIqUigFW7cdK6GHoB64ubY4qXQNYknoUeks4Wz7CUA== dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-module-imports" "^7.21.4" + "@babel/helper-plugin-utils" "^7.20.2" babel-plugin-polyfill-corejs2 "^0.3.3" babel-plugin-polyfill-corejs3 "^0.6.0" babel-plugin-polyfill-regenerator "^0.4.1" @@ -993,13 +866,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-spread@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz#dd60b4620c2fec806d60cfaae364ec2188d593b6" - integrity sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w== +"@babel/plugin-transform-spread@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz#c2d83e0b99d3bf83e07b11995ee24bf7ca09401e" + integrity sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" "@babel/plugin-transform-sticky-regex@^7.18.6": version "7.18.6" @@ -1022,13 +895,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-typescript@^7.18.6": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.0.tgz#2c7ec62b8bfc21482f3748789ba294a46a375169" - integrity sha512-xOAsAFaun3t9hCwZ13Qe7gq423UgMZ6zAgmLxeGGapFqlT/X3L5qT2btjiVLlFn7gWtMaVyceS5VxGAuKbgizw== +"@babel/plugin-transform-typescript@^7.21.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz#316c5be579856ea890a57ebc5116c5d064658f2b" + integrity sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.19.0" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.21.0" + "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-typescript" "^7.20.0" "@babel/plugin-transform-unicode-escapes@^7.18.10": @@ -1046,31 +920,31 @@ "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/preset-env@^7.11.0": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.20.2.tgz#9b1642aa47bb9f43a86f9630011780dab7f86506" - integrity sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg== +"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.21.4.tgz#a952482e634a8dd8271a3fe5459a16eb10739c58" + integrity sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw== dependencies: - "@babel/compat-data" "^7.20.1" - "@babel/helper-compilation-targets" "^7.20.0" + "@babel/compat-data" "^7.21.4" + "@babel/helper-compilation-targets" "^7.21.4" "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-option" "^7.18.6" + "@babel/helper-validator-option" "^7.21.0" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-async-generator-functions" "^7.20.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.20.7" + "@babel/plugin-proposal-async-generator-functions" "^7.20.7" "@babel/plugin-proposal-class-properties" "^7.18.6" - "@babel/plugin-proposal-class-static-block" "^7.18.6" + "@babel/plugin-proposal-class-static-block" "^7.21.0" "@babel/plugin-proposal-dynamic-import" "^7.18.6" "@babel/plugin-proposal-export-namespace-from" "^7.18.9" "@babel/plugin-proposal-json-strings" "^7.18.6" - "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" + "@babel/plugin-proposal-logical-assignment-operators" "^7.20.7" "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" "@babel/plugin-proposal-numeric-separator" "^7.18.6" - "@babel/plugin-proposal-object-rest-spread" "^7.20.2" + "@babel/plugin-proposal-object-rest-spread" "^7.20.7" "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" - "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-optional-chaining" "^7.21.0" "@babel/plugin-proposal-private-methods" "^7.18.6" - "@babel/plugin-proposal-private-property-in-object" "^7.18.6" + "@babel/plugin-proposal-private-property-in-object" "^7.21.0" "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" @@ -1087,121 +961,40 @@ "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.18.6" - "@babel/plugin-transform-async-to-generator" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.20.7" + "@babel/plugin-transform-async-to-generator" "^7.20.7" "@babel/plugin-transform-block-scoped-functions" "^7.18.6" - "@babel/plugin-transform-block-scoping" "^7.20.2" - "@babel/plugin-transform-classes" "^7.20.2" - "@babel/plugin-transform-computed-properties" "^7.18.9" - "@babel/plugin-transform-destructuring" "^7.20.2" + "@babel/plugin-transform-block-scoping" "^7.21.0" + "@babel/plugin-transform-classes" "^7.21.0" + "@babel/plugin-transform-computed-properties" "^7.20.7" + "@babel/plugin-transform-destructuring" "^7.21.3" "@babel/plugin-transform-dotall-regex" "^7.18.6" "@babel/plugin-transform-duplicate-keys" "^7.18.9" "@babel/plugin-transform-exponentiation-operator" "^7.18.6" - "@babel/plugin-transform-for-of" "^7.18.8" + "@babel/plugin-transform-for-of" "^7.21.0" "@babel/plugin-transform-function-name" "^7.18.9" "@babel/plugin-transform-literals" "^7.18.9" "@babel/plugin-transform-member-expression-literals" "^7.18.6" - "@babel/plugin-transform-modules-amd" "^7.19.6" - "@babel/plugin-transform-modules-commonjs" "^7.19.6" - "@babel/plugin-transform-modules-systemjs" "^7.19.6" + "@babel/plugin-transform-modules-amd" "^7.20.11" + "@babel/plugin-transform-modules-commonjs" "^7.21.2" + "@babel/plugin-transform-modules-systemjs" "^7.20.11" "@babel/plugin-transform-modules-umd" "^7.18.6" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.20.5" "@babel/plugin-transform-new-target" "^7.18.6" "@babel/plugin-transform-object-super" "^7.18.6" - "@babel/plugin-transform-parameters" "^7.20.1" + "@babel/plugin-transform-parameters" "^7.21.3" "@babel/plugin-transform-property-literals" "^7.18.6" - "@babel/plugin-transform-regenerator" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.20.5" "@babel/plugin-transform-reserved-words" "^7.18.6" "@babel/plugin-transform-shorthand-properties" "^7.18.6" - "@babel/plugin-transform-spread" "^7.19.0" + "@babel/plugin-transform-spread" "^7.20.7" "@babel/plugin-transform-sticky-regex" "^7.18.6" "@babel/plugin-transform-template-literals" "^7.18.9" "@babel/plugin-transform-typeof-symbol" "^7.18.9" "@babel/plugin-transform-unicode-escapes" "^7.18.10" "@babel/plugin-transform-unicode-regex" "^7.18.6" "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.20.2" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - core-js-compat "^3.25.1" - semver "^6.3.0" - -"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.19.4.tgz#4c91ce2e1f994f717efb4237891c3ad2d808c94b" - integrity sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg== - dependencies: - "@babel/compat-data" "^7.19.4" - "@babel/helper-compilation-targets" "^7.19.3" - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-async-generator-functions" "^7.19.1" - "@babel/plugin-proposal-class-properties" "^7.18.6" - "@babel/plugin-proposal-class-static-block" "^7.18.6" - "@babel/plugin-proposal-dynamic-import" "^7.18.6" - "@babel/plugin-proposal-export-namespace-from" "^7.18.9" - "@babel/plugin-proposal-json-strings" "^7.18.6" - "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" - "@babel/plugin-proposal-numeric-separator" "^7.18.6" - "@babel/plugin-proposal-object-rest-spread" "^7.19.4" - "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" - "@babel/plugin-proposal-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-private-methods" "^7.18.6" - "@babel/plugin-proposal-private-property-in-object" "^7.18.6" - "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.18.6" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.18.6" - "@babel/plugin-transform-async-to-generator" "^7.18.6" - "@babel/plugin-transform-block-scoped-functions" "^7.18.6" - "@babel/plugin-transform-block-scoping" "^7.19.4" - "@babel/plugin-transform-classes" "^7.19.0" - "@babel/plugin-transform-computed-properties" "^7.18.9" - "@babel/plugin-transform-destructuring" "^7.19.4" - "@babel/plugin-transform-dotall-regex" "^7.18.6" - "@babel/plugin-transform-duplicate-keys" "^7.18.9" - "@babel/plugin-transform-exponentiation-operator" "^7.18.6" - "@babel/plugin-transform-for-of" "^7.18.8" - "@babel/plugin-transform-function-name" "^7.18.9" - "@babel/plugin-transform-literals" "^7.18.9" - "@babel/plugin-transform-member-expression-literals" "^7.18.6" - "@babel/plugin-transform-modules-amd" "^7.18.6" - "@babel/plugin-transform-modules-commonjs" "^7.18.6" - "@babel/plugin-transform-modules-systemjs" "^7.19.0" - "@babel/plugin-transform-modules-umd" "^7.18.6" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" - "@babel/plugin-transform-new-target" "^7.18.6" - "@babel/plugin-transform-object-super" "^7.18.6" - "@babel/plugin-transform-parameters" "^7.18.8" - "@babel/plugin-transform-property-literals" "^7.18.6" - "@babel/plugin-transform-regenerator" "^7.18.6" - "@babel/plugin-transform-reserved-words" "^7.18.6" - "@babel/plugin-transform-shorthand-properties" "^7.18.6" - "@babel/plugin-transform-spread" "^7.19.0" - "@babel/plugin-transform-sticky-regex" "^7.18.6" - "@babel/plugin-transform-template-literals" "^7.18.9" - "@babel/plugin-transform-typeof-symbol" "^7.18.9" - "@babel/plugin-transform-unicode-escapes" "^7.18.10" - "@babel/plugin-transform-unicode-regex" "^7.18.6" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.19.4" + "@babel/types" "^7.21.4" babel-plugin-polyfill-corejs2 "^0.3.3" babel-plugin-polyfill-corejs3 "^0.6.0" babel-plugin-polyfill-regenerator "^0.4.1" @@ -1232,97 +1025,57 @@ "@babel/plugin-transform-react-pure-annotations" "^7.18.6" "@babel/preset-typescript@^7.16.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz#ce64be3e63eddc44240c6358daefac17b3186399" - integrity sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ== + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.21.4.tgz#b913ac8e6aa8932e47c21b01b4368d8aa239a529" + integrity sha512-sMLNWY37TCdRH/bJ6ZeeOH1nPuanED7Ai9Y/vH31IPqalioJ6ZNFUWONsakhv4r4n+I6gm5lmoE0olkgib/j/A== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-transform-typescript" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-validator-option" "^7.21.0" + "@babel/plugin-syntax-jsx" "^7.21.4" + "@babel/plugin-transform-modules-commonjs" "^7.21.2" + "@babel/plugin-transform-typescript" "^7.21.3" -"@babel/runtime-corejs3@^7.10.2": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.20.0.tgz#56ef7af3cd23d1570969809a5a8782e774e0141a" - integrity sha512-v1JH7PeAAGBEyTQM9TqojVl+b20zXtesFKCJHu50xMxZKD1fX0TKaKHPsZfFkXfs7D1M9M6Eeqg1FkJ3a0x2dA== - dependencies: - core-js-pure "^3.25.1" - regenerator-runtime "^0.13.10" +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.0.tgz#824a9ef325ffde6f78056059db3168c08785e24a" - integrity sha512-NDYdls71fTXoU8TZHfbBWg7DiZfNzClcKui/+kyi6ppD2L1qnWW3VV6CjtaBXSUGGhiTWJ6ereOIkUvenif66Q== - dependencies: - regenerator-runtime "^0.13.10" - -"@babel/runtime@^7.11.2": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9" - integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg== - dependencies: - regenerator-runtime "^0.13.10" - -"@babel/runtime@^7.13.10": - version "7.20.13" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.13.tgz#7055ab8a7cff2b8f6058bf6ae45ff84ad2aded4b" - integrity sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA== +"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.6", "@babel/runtime@^7.16.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" + integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== dependencies: regenerator-runtime "^0.13.11" -"@babel/template@^7.18.10", "@babel/template@^7.3.3": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" - integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== +"@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.18.10" - "@babel/types" "^7.18.10" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" -"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.19.6", "@babel/traverse@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.0.tgz#538c4c6ce6255f5666eba02252a7b59fc2d5ed98" - integrity sha512-5+cAXQNARgjRUK0JWu2UBwja4JLSO/rBMPJzpsKb+oBF5xlUuCfljQepS4XypBQoiigL0VQjTZy6WiONtUdScQ== +"@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4", "@babel/traverse@^7.7.2": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.4.tgz#a836aca7b116634e97a6ed99976236b3282c9d36" + integrity sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q== dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.20.0" + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.4" "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" + "@babel/helper-function-name" "^7.21.0" "@babel/helper-hoist-variables" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.20.0" - "@babel/types" "^7.20.0" + "@babel/parser" "^7.21.4" + "@babel/types" "^7.21.4" debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.20.1", "@babel/traverse@^7.7.2": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8" - integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.20.1" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.20.1" - "@babel/types" "^7.20.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.19.4", "@babel/types@^7.20.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.0.tgz#52c94cf8a7e24e89d2a194c25c35b17a64871479" - integrity sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg== - dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" - to-fast-properties "^2.0.0" - -"@babel/types@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842" - integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog== +"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.4.tgz#2d5d6bb7908699b3b416409ffd3b5daa25b030d4" + integrity sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA== dependencies: "@babel/helper-string-parser" "^7.19.4" "@babel/helper-validator-identifier" "^7.19.1" @@ -1440,9 +1193,21 @@ integrity sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g== "@csstools/selector-specificity@^2.0.0", "@csstools/selector-specificity@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36" - integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg== + version "2.2.0" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016" + integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw== + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724" + integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ== "@eslint/eslintrc@^0.4.3": version "0.4.3" @@ -1459,21 +1224,26 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@eslint/eslintrc@^1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95" - integrity sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg== +"@eslint/eslintrc@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02" + integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" - globals "^13.15.0" + espree "^9.5.1" + globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@8.38.0": + version "8.38.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.38.0.tgz#73a8a0d8aa8a8e6fe270431c5e72ae91b5337892" + integrity sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g== + "@excalidraw/eslint-config@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@excalidraw/eslint-config/-/eslint-config-1.0.0.tgz#1cc527a88cfe20fd730496c1b631c3aecf9c825e" @@ -1708,10 +1478,30 @@ resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.4.1.tgz#600f2275ff54739ad5ac0102f1467b8963cd5f71" integrity sha512-0yPjzuzGMkW1GkrC8yWsiN7vt1OzkMIi9HgxRmKREZl2wnNPOKo/yScTjXf/O57HM8dltqxPF6jlNLFVtc2qdw== +"@floating-ui/core@^0.7.3": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86" + integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg== + +"@floating-ui/dom@^0.5.3": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-0.5.4.tgz#4eae73f78bcd4bd553ae2ade30e6f1f9c73fe3f1" + integrity sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg== + dependencies: + "@floating-ui/core" "^0.7.3" + +"@floating-ui/react-dom@0.7.2": + version "0.7.2" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-0.7.2.tgz#0bf4ceccb777a140fc535c87eb5d6241c8e89864" + integrity sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg== + dependencies: + "@floating-ui/dom" "^0.5.3" + use-isomorphic-layout-effect "^1.1.1" + "@grpc/grpc-js@^1.0.0": - version "1.7.3" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.7.3.tgz#f2ea79f65e31622d7f86d4b4c9ae38f13ccab99a" - integrity sha512-H9l79u4kJ2PVSxUNA08HMYAnUBLj9v6KjYQ7SQ71hOZcEXhShE/y5iQCesP8+6/Ik/7i2O0a10bPquIcYfufog== + version "1.8.13" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.13.tgz#e775685962909b76f8d4b813833c3d123867165b" + integrity sha512-iY3jsdfbc0ARoCLFvbvUB8optgyb0r1XLPb142u+QtgBcKJYkCIFt3Fd/881KqjLYWjsBJF57N3b8Eop9NDfUA== dependencies: "@grpc/proto-loader" "^0.7.0" "@types/node" ">=12.12.47" @@ -1725,9 +1515,9 @@ protobufjs "^6.8.6" "@grpc/proto-loader@^0.7.0": - version "0.7.3" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.3.tgz#75a6f95b51b85c5078ac7394da93850c32d36bb8" - integrity sha512-5dAvoZwna2Py3Ef96Ux9jIkp3iZ62TUsV00p3wVBPNX5K178UbNi8Q7gQVqwXT1Yq9RejIGG9G2IPEo93T6RcA== + version "0.7.6" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.6.tgz#b71fdf92b184af184b668c4e9395a5ddc23d61de" + integrity sha512-QyAXR8Hyh7uMDmveWxDSUcJr9NAWaZ2I6IXgAYvQmfflwouTM+rArE2eEaCtLlRqO81j7pRLCt81IefUei6Zbw== dependencies: "@types/long" "^4.0.1" lodash.camelcase "^4.3.0" @@ -1735,10 +1525,10 @@ protobufjs "^7.0.0" yargs "^16.2.0" -"@humanwhocodes/config-array@^0.11.6": - version "0.11.7" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.7.tgz#38aec044c6c828f6ed51d5d7ae3d9b9faf6dbb0f" - integrity sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw== +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" @@ -1847,12 +1637,12 @@ "@types/node" "*" jest-mock "^27.5.1" -"@jest/expect-utils@^29.2.2": - version "29.2.2" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.2.2.tgz#460a5b5a3caf84d4feb2668677393dd66ff98665" - integrity sha512-vwnVmrVhTmGgQzyvcpze08br91OL61t9O0lJMDyb6Y/D8EKQ9V7rGUb/p7PDt0GPzK0zFYqXWFo4EO2legXmkg== +"@jest/expect-utils@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036" + integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== dependencies: - jest-get-type "^29.2.0" + jest-get-type "^29.4.3" "@jest/fake-timers@^27.5.1": version "27.5.1" @@ -1913,12 +1703,12 @@ dependencies: "@sinclair/typebox" "^0.24.1" -"@jest/schemas@^29.0.0": - version "29.0.0" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a" - integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== dependencies: - "@sinclair/typebox" "^0.24.1" + "@sinclair/typebox" "^0.25.16" "@jest/source-map@^27.5.1": version "27.5.1" @@ -2003,30 +1793,22 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jest/types@^29.2.1": - version "29.2.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.2.1.tgz#ec9c683094d4eb754e41e2119d8bdaef01cf6da0" - integrity sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw== +"@jest/types@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" + integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== dependencies: - "@jest/schemas" "^29.0.0" + "@jest/schemas" "^29.4.3" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== dependencies: "@jridgewell/set-array" "^1.0.1" "@jridgewell/sourcemap-codec" "^1.4.10" @@ -2037,28 +1819,33 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== -"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": +"@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== "@jridgewell/source-map@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" - integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" + integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg== dependencies: "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== dependencies: "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" @@ -2097,9 +1884,9 @@ fastq "^1.6.0" "@pmmmwh/react-refresh-webpack-plugin@^0.5.3": - version "0.5.9" - resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.9.tgz#35aae6624a6270ca7ad755800b7eec417fa6f830" - integrity sha512-7QV4cqUwhkDIHpMAZ9mestSJ2DMIotVTbOUwbiudhjCRTAWWKIaBecELiEM2LT3AHFeOAaHIcFu4dbXjX+9GBA== + version "0.5.10" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz#2eba163b8e7dbabb4ce3609ab5e32ab63dda3ef8" + integrity sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA== dependencies: ansi-html-community "^0.0.8" common-path-prefix "^3.0.0" @@ -2107,7 +1894,7 @@ error-stack-parser "^2.0.6" find-up "^5.0.0" html-entities "^2.1.0" - loader-utils "^2.0.3" + loader-utils "^2.0.4" schema-utils "^3.0.0" source-map "^0.7.3" @@ -2171,6 +1958,14 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-arrow@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.1.tgz#5246adf79e97f89e819af68da51ddcf349ecf1c4" + integrity sha512-1yientwXqXcErDHEv8av9ZVNEBldH8L9scVR3is20lL+jOCfcJyMFZFEY5cgIrgexsq1qggSXqiEL/d/4f+QXA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-collection@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.1.tgz#259506f97c6703b36291826768d3c1337edd1de5" @@ -2203,6 +1998,35 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-dismissable-layer@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.2.tgz#f04d1061bddf00b1ca304148516b9ddc62e45fb2" + integrity sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.0" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-escape-keydown" "1.0.2" + +"@radix-ui/react-focus-guards@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz#339c1c69c41628c1a5e655f15f7020bf11aa01fa" + integrity sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-focus-scope@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.1.tgz#faea8c25f537c5a5c38c50914b63722db0e7f951" + integrity sha512-Ej2MQTit8IWJiS2uuujGUmxXjF/y5xZptIIQnyd2JHLwtV0R2j9NRVoRj/1j/gJ7e3REdaBw4Hjf4a1ImhkZcQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-id@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.0.tgz#8d43224910741870a45a8c9d092f25887bb6d11e" @@ -2211,6 +2035,53 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-layout-effect" "1.0.0" +"@radix-ui/react-popover@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.0.3.tgz#65ae2ee1fca2d7fd750308549eb8e0857c6160fe" + integrity sha512-YwedSukfWsyJs3/yP3yXUq44k4/JBe3jqU63Z8v2i19qZZ3dsx32oma17ztgclWPNuqp3A+Xa9UiDlZHyVX8Vg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.0" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-context" "1.0.0" + "@radix-ui/react-dismissable-layer" "1.0.2" + "@radix-ui/react-focus-guards" "1.0.0" + "@radix-ui/react-focus-scope" "1.0.1" + "@radix-ui/react-id" "1.0.0" + "@radix-ui/react-popper" "1.1.0" + "@radix-ui/react-portal" "1.0.1" + "@radix-ui/react-presence" "1.0.0" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-slot" "1.0.1" + "@radix-ui/react-use-controllable-state" "1.0.0" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + +"@radix-ui/react-popper@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.0.tgz#2be7e4c0cd4581f54277ca33a981c9037d2a8e60" + integrity sha512-07U7jpI0dZcLRAxT7L9qs6HecSoPhDSJybF7mEGHJDBDv+ZoGCvIlva0s+WxMXwJEav+ckX3hAlXBtnHmuvlCQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@floating-ui/react-dom" "0.7.2" + "@radix-ui/react-arrow" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-context" "1.0.0" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-layout-effect" "1.0.0" + "@radix-ui/react-use-rect" "1.0.0" + "@radix-ui/react-use-size" "1.0.0" + "@radix-ui/rect" "1.0.0" + +"@radix-ui/react-portal@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.1.tgz#169c5a50719c2bb0079cf4c91a27aa6d37e5dd33" + integrity sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-presence@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.0.tgz#814fe46df11f9a468808a6010e3f3ca7e0b2e84a" @@ -2282,6 +2153,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-callback-ref" "1.0.0" +"@radix-ui/react-use-escape-keydown@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz#09ab6455ab240b4f0a61faf06d4e5132c4d639f6" + integrity sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-layout-effect@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz#2fc19e97223a81de64cd3ba1dc42ceffd82374dc" @@ -2289,6 +2168,29 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-use-rect@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz#b040cc88a4906b78696cd3a32b075ed5b1423b3e" + integrity sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/rect" "1.0.0" + +"@radix-ui/react-use-size@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz#a0b455ac826749419f6354dc733e2ca465054771" + integrity sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.0" + +"@radix-ui/rect@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.0.tgz#0dc8e6a829ea2828d53cbc94b81793ba6383bf3c" + integrity sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg== + dependencies: + "@babel/runtime" "^7.13.10" + "@rollup/plugin-babel@^5.2.0": version "5.3.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" @@ -2398,10 +2300,15 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== + "@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + version "1.8.6" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" + integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== dependencies: type-detect "4.0.8" @@ -2526,13 +2433,13 @@ loader-utils "^2.0.0" "@testing-library/dom@^8.0.0": - version "8.19.0" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.19.0.tgz#bd3f83c217ebac16694329e413d9ad5fdcfd785f" - integrity sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A== + version "8.20.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.20.0.tgz#914aa862cef0f5e89b98cc48e3445c4c921010f6" + integrity sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA== dependencies: "@babel/code-frame" "^7.10.4" "@babel/runtime" "^7.12.5" - "@types/aria-query" "^4.2.0" + "@types/aria-query" "^5.0.1" aria-query "^5.0.0" chalk "^4.1.0" dom-accessibility-api "^0.5.9" @@ -2578,29 +2485,18 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== -"@types/aria-query@^4.2.0": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" - integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== +"@types/aria-query@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.1.tgz#3286741fb8f1e1580ac28784add4c7a1d49bdfbc" + integrity sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q== -"@types/babel__core@^7.0.0": - version "7.1.19" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" - integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" + integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__core@^7.1.14": - version "7.1.20" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.20.tgz#e168cdd612c92a2d335029ed62ac94c95b362359" - integrity sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" "@types/babel__generator" "*" "@types/babel__template" "*" "@types/babel__traverse" "*" @@ -2621,9 +2517,9 @@ "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.2.tgz#235bf339d17185bdec25e024ca19cce257cc7309" - integrity sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg== + version "7.18.3" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.3.tgz#dfc508a85781e5698d5b33443416b6268c4b3e8d" + integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== dependencies: "@babel/types" "^7.3.0" @@ -2671,9 +2567,9 @@ "@types/estree" "*" "@types/eslint@*", "@types/eslint@^7.29.0 || ^8.4.1": - version "8.4.10" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.10.tgz#19731b9685c19ed1552da7052b6f668ed7eb64bb" - integrity sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw== + version "8.37.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.37.0.tgz#29cebc6c2a3ac7fea7113207bf5a828fdf4d7ef1" + integrity sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -2693,29 +2589,29 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== -"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": - version "4.17.31" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz#a1139efeab4e7323834bb0226e62ac019f474b2f" - integrity sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q== +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": + version "4.17.33" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" + integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" "@types/express@*", "@types/express@^4.17.13": - version "4.17.14" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.14.tgz#143ea0557249bc1b3b54f15db4c81c3d4eb3569c" - integrity sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg== + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== dependencies: "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.18" + "@types/express-serve-static-core" "^4.17.33" "@types/qs" "*" "@types/serve-static" "*" "@types/graceful-fs@^4.1.2": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" - integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== dependencies: "@types/node" "*" @@ -2725,9 +2621,9 @@ integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== "@types/http-proxy@^1.17.8": - version "1.17.9" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a" - integrity sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw== + version "1.17.10" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.10.tgz#e576c8e4a0cc5c6a138819025a88e167ebb38d6c" + integrity sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g== dependencies: "@types/node" "*" @@ -2751,9 +2647,9 @@ "@types/istanbul-lib-report" "*" "@types/jest@*": - version "29.2.0" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.2.0.tgz#fa98e08b46ab119f1a74a9552c48c589f5378a96" - integrity sha512-KO7bPV21d65PKwv3LLsD8Jn3E05pjNjRZvkm+YTacWhVmykAb07wW6IkZUmQAltwQafNcDUEUrMO2h3jeBSisg== + version "29.5.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.0.tgz#337b90bbcfe42158f39c2fb5619ad044bbb518ac" + integrity sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -2784,9 +2680,9 @@ "@types/lodash" "*" "@types/lodash@*": - version "4.14.186" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.186.tgz#862e5514dd7bd66ada6c70ee5fce844b06c8ee97" - integrity sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw== + version "4.14.192" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.192.tgz#5790406361a2852d332d41635d927f1600811285" + integrity sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A== "@types/long@^4.0.1": version "4.0.2" @@ -2799,9 +2695,9 @@ integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== "@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0": - version "18.11.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.8.tgz#16d222a58d4363a2a359656dd20b28414de5d265" - integrity sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A== + version "18.15.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" + integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== "@types/pako@1.0.3": version "1.0.3" @@ -2819,9 +2715,9 @@ integrity sha512-13SEyETRE5psd9bE0AmN+0M1tannde2fwHfLVaVIljkbL9V0OfFvKwCicyeDvVYLkmjQWEydbAlsDsmjrdyTOg== "@types/prettier@^2.1.5": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.1.tgz#dfd20e2dc35f027cdd6c1908e80a5ddc7499670e" - integrity sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow== + version "2.7.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" + integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== "@types/prop-types@*": version "15.7.5" @@ -2851,16 +2747,16 @@ "@types/react" "*" "@types/react-dom@<18.0.0": - version "17.0.18" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.18.tgz#8f7af38f5d9b42f79162eea7492e5a1caff70dc2" - integrity sha512-rLVtIfbwyur2iFKykP2w0pl/1unw26b5td16d5xMgp7/yjTHomkyxPYChFoCr/FtEX1lN9wY6lFj1qvKdS5kDw== + version "17.0.19" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.19.tgz#36feef3aa35d045cacd5ed60fe0eef5272f19492" + integrity sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ== dependencies: "@types/react" "^17" "@types/react@*": - version "18.0.24" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.24.tgz#2f79ed5b27f08d05107aab45c17919754cc44c20" - integrity sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q== + version "18.0.34" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.34.tgz#e553444a578f023e6e1ac499514688fb80b0a984" + integrity sha512-NO1UO8941541CJl1BeOXi8a9dNKFK09Gnru5ZJqkm4Q3/WoQJtHvmwt0VX0SB9YCEwe7TfSSxDuaNmx6H2BAIQ== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2876,9 +2772,9 @@ csstype "^3.0.2" "@types/react@^17": - version "17.0.52" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.52.tgz#10d8b907b5c563ac014a541f289ae8eaa9bf2e9b" - integrity sha512-vwk8QqVODi0VaZZpDXQCmEmiOuyjEFPY7Ttaw5vjM112LOq37yz1CDJGrRJwA1fYEq4Iitd5rnjd1yWAc/bT+A== + version "17.0.57" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.57.tgz#341152f222222075caf020ae6e0e68b9b835404c" + integrity sha512-e4msYpu5QDxzNrXDHunU/VPyv2M1XemGG/p7kfCjUiPtlLDCWLGQfgAMng6YyisWYxZ09mYdQlmMnyS0NfZdEg== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2902,9 +2798,9 @@ integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== "@types/scheduler@*": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + version "0.16.3" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" + integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== "@types/semver@^7.3.12": version "7.3.13" @@ -2919,9 +2815,9 @@ "@types/express" "*" "@types/serve-static@*", "@types/serve-static@^1.13.10": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" - integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== + version "1.15.1" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d" + integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== dependencies: "@types/mime" "*" "@types/node" "*" @@ -2951,14 +2847,14 @@ "@types/jest" "*" "@types/trusted-types@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" - integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.3.tgz#a136f83b0758698df454e328759dbd3d44555311" + integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g== "@types/ws@^8.5.1": - version "8.5.3" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" - integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== + version "8.5.4" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" + integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg== dependencies: "@types/node" "*" @@ -2968,107 +2864,108 @@ integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== "@types/yargs@^16.0.0": - version "16.0.4" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" - integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + version "16.0.5" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.5.tgz#12cc86393985735a283e387936398c2f9e5f88e3" + integrity sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ== dependencies: "@types/yargs-parser" "*" "@types/yargs@^17.0.8": - version "17.0.13" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.13.tgz#34cced675ca1b1d51fcf4d34c3c6f0fa142a5c76" - integrity sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg== + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== dependencies: "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@^5.5.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.43.0.tgz#4a5248eb31b454715ddfbf8cfbf497529a0a78bc" - integrity sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA== + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz#b1d4b0ad20243269d020ef9bbb036a40b0849829" + integrity sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA== dependencies: - "@typescript-eslint/scope-manager" "5.43.0" - "@typescript-eslint/type-utils" "5.43.0" - "@typescript-eslint/utils" "5.43.0" + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.58.0" + "@typescript-eslint/type-utils" "5.58.0" + "@typescript-eslint/utils" "5.58.0" debug "^4.3.4" + grapheme-splitter "^1.0.4" ignore "^5.2.0" natural-compare-lite "^1.4.0" - regexpp "^3.2.0" semver "^7.3.7" tsutils "^3.21.0" "@typescript-eslint/experimental-utils@^5.0.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.43.0.tgz#2fbea6ea89e59e780e42ca65bc39fc830db95ed4" - integrity sha512-WkT637CumTJbm/hRbFfnHBMgfUYTKr08LitVsD7gQId7bi6rnkx3pu3jac67lmp5ObW4MpJ9SNFZAIOUB/Qbsw== + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.58.0.tgz#157af1376add1a945c4559eef25114f0a29f49e1" + integrity sha512-LA/sRPaynZlrlYxdefrZbMx8dqs/1Kc0yNG+XOk5CwwZx7tTv263ix3AJNioF0YBVt7hADpAUR20owl6pv4MIQ== dependencies: - "@typescript-eslint/utils" "5.43.0" + "@typescript-eslint/utils" "5.58.0" "@typescript-eslint/parser@^5.5.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.43.0.tgz#9c86581234b88f2ba406f0b99a274a91c11630fd" - integrity sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug== + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.58.0.tgz#2ac4464cf48bef2e3234cb178ede5af352dddbc6" + integrity sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ== dependencies: - "@typescript-eslint/scope-manager" "5.43.0" - "@typescript-eslint/types" "5.43.0" - "@typescript-eslint/typescript-estree" "5.43.0" + "@typescript-eslint/scope-manager" "5.58.0" + "@typescript-eslint/types" "5.58.0" + "@typescript-eslint/typescript-estree" "5.58.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.43.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz#566e46303392014d5d163704724872e1f2dd3c15" - integrity sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw== +"@typescript-eslint/scope-manager@5.58.0": + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz#5e023a48352afc6a87be6ce3c8e763bc9e2f0bc8" + integrity sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA== dependencies: - "@typescript-eslint/types" "5.43.0" - "@typescript-eslint/visitor-keys" "5.43.0" + "@typescript-eslint/types" "5.58.0" + "@typescript-eslint/visitor-keys" "5.58.0" -"@typescript-eslint/type-utils@5.43.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz#91110fb827df5161209ecca06f70d19a96030be6" - integrity sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg== +"@typescript-eslint/type-utils@5.58.0": + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz#f7d5b3971483d4015a470d8a9e5b8a7d10066e52" + integrity sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w== dependencies: - "@typescript-eslint/typescript-estree" "5.43.0" - "@typescript-eslint/utils" "5.43.0" + "@typescript-eslint/typescript-estree" "5.58.0" + "@typescript-eslint/utils" "5.58.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.43.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.43.0.tgz#e4ddd7846fcbc074325293515fa98e844d8d2578" - integrity sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg== +"@typescript-eslint/types@5.58.0": + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.58.0.tgz#54c490b8522c18986004df7674c644ffe2ed77d8" + integrity sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g== -"@typescript-eslint/typescript-estree@5.43.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz#b6883e58ba236a602c334be116bfc00b58b3b9f2" - integrity sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg== +"@typescript-eslint/typescript-estree@5.58.0": + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz#4966e6ff57eaf6e0fce2586497edc097e2ab3e61" + integrity sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q== dependencies: - "@typescript-eslint/types" "5.43.0" - "@typescript-eslint/visitor-keys" "5.43.0" + "@typescript-eslint/types" "5.58.0" + "@typescript-eslint/visitor-keys" "5.58.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.43.0", "@typescript-eslint/utils@^5.13.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.43.0.tgz#00fdeea07811dbdf68774a6f6eacfee17fcc669f" - integrity sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A== +"@typescript-eslint/utils@5.58.0", "@typescript-eslint/utils@^5.43.0": + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.58.0.tgz#430d7c95f23ec457b05be5520c1700a0dfd559d5" + integrity sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ== dependencies: + "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.43.0" - "@typescript-eslint/types" "5.43.0" - "@typescript-eslint/typescript-estree" "5.43.0" + "@typescript-eslint/scope-manager" "5.58.0" + "@typescript-eslint/types" "5.58.0" + "@typescript-eslint/typescript-estree" "5.58.0" eslint-scope "^5.1.1" - eslint-utils "^3.0.0" semver "^7.3.7" -"@typescript-eslint/visitor-keys@5.43.0": - version "5.43.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz#cbbdadfdfea385310a20a962afda728ea106befa" - integrity sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg== +"@typescript-eslint/visitor-keys@5.58.0": + version "5.58.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz#eb9de3a61d2331829e6761ce7fd13061781168b4" + integrity sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA== dependencies: - "@typescript-eslint/types" "5.43.0" + "@typescript-eslint/types" "5.58.0" eslint-visitor-keys "^3.3.0" "@webassemblyjs/ast@1.11.1": @@ -3233,34 +3130,25 @@ acorn-jsx@^5.3.1, acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-node@^1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" - integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== - dependencies: - acorn "^7.0.0" - acorn-walk "^7.0.0" - xtend "^4.0.2" - -acorn-walk@^7.0.0, acorn-walk@^7.1.1: +acorn-walk@^7.1.1: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^7.0.0, acorn@^7.1.1, acorn@^7.4.0: +acorn@^7.1.1, acorn@^7.4.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== acorn@^8.2.4, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: - version "8.8.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" - integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== address@^1.0.1, address@^1.1.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/address/-/address-1.2.1.tgz#25bb61095b7522d65b357baa11bc05492d4c8acd" - integrity sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA== + version "1.2.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" + integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== adjust-sourcemap-loader@^4.0.0: version "4.0.0" @@ -3319,20 +3207,10 @@ ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.6.0, ajv@^8.8.0: - version "8.11.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.2.tgz#aecb20b50607acf2569b6382167b65a96008bb78" - integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ajv@^8.0.1: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== +ajv@^8.0.0, ajv@^8.0.1, ajv@^8.6.0, ajv@^8.8.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -3390,10 +3268,15 @@ ansi-styles@^6.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + anymatch@^3.0.3, anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -3415,21 +3298,28 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-query@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" - integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA== +aria-hidden@^1.1.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" + integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== dependencies: - "@babel/runtime" "^7.10.2" - "@babel/runtime-corejs3" "^7.10.2" + tslib "^2.0.0" -aria-query@^5.0.0: +aria-query@^5.0.0, aria-query@^5.1.3: version "5.1.3" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== dependencies: deep-equal "^2.0.5" +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -3440,18 +3330,7 @@ array-flatten@^2.1.2: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== -array-includes@^3.1.4, array-includes@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" - integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.19.5" - get-intrinsic "^1.1.1" - is-string "^1.0.7" - -array-includes@^3.1.6: +array-includes@^3.1.5, array-includes@^3.1.6: version "3.1.6" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== @@ -3467,14 +3346,14 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.flat@^1.2.5: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b" - integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw== +array.prototype.flat@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" + integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" array.prototype.flatmap@^1.3.1: @@ -3487,14 +3366,14 @@ array.prototype.flatmap@^1.3.1: es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" -array.prototype.reduce@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz#8167e80089f78bff70a99e20bd4201d4663b0a6f" - integrity sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw== +array.prototype.reduce@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz#6b20b0daa9d9734dd6bc7ea66b5bbce395471eac" + integrity sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" es-array-method-boxes-properly "^1.0.0" is-string "^1.0.7" @@ -3567,12 +3446,12 @@ atob@^2.1.2: integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== autoprefixer@^10.4.13: - version "10.4.13" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.13.tgz#b5136b59930209a321e9fa3dca2e7c4d223e83a8" - integrity sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg== + version "10.4.14" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d" + integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ== dependencies: - browserslist "^4.21.4" - caniuse-lite "^1.0.30001426" + browserslist "^4.21.5" + caniuse-lite "^1.0.30001464" fraction.js "^4.2.0" normalize-range "^0.1.2" picocolors "^1.0.0" @@ -3583,15 +3462,17 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -axe-core@^4.4.3: - version "4.5.0" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.5.0.tgz#6efe2ecdba205fcc9d7ddb3d48c2cf630f70eb5e" - integrity sha512-4+rr8eQ7+XXS5nZrKcMO/AikHL0hVqy+lHWAnE3xdHl+aguag8SOQ6eEqLexwLNWgXIMfunGuD3ON1/6Kyet0A== +axe-core@^4.6.2: + version "4.6.3" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.6.3.tgz#fc0db6fdb65cc7a80ccf85286d91d64ababa3ece" + integrity sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg== -axobject-query@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" - integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== +axobject-query@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1" + integrity sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg== + dependencies: + deep-equal "^2.0.5" babel-jest@^27.4.2, babel-jest@^27.5.1: version "27.5.1" @@ -3810,9 +3691,9 @@ body-parser@1.20.1: unpipe "1.0.0" bonjour-service@^1.0.11: - version "1.0.14" - resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.14.tgz#c346f5bc84e87802d08f8d5a60b93f758e514ee7" - integrity sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ== + version "1.1.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.1.tgz#960948fa0e0153f5d26743ab15baf8e33752c135" + integrity sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg== dependencies: array-flatten "^2.1.2" dns-equal "^1.0.0" @@ -3856,15 +3737,15 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.21.3, browserslist@^4.21.4: - version "4.21.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" - integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5: + version "4.21.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" + integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== dependencies: - caniuse-lite "^1.0.30001400" - electron-to-chromium "^1.4.251" - node-releases "^2.0.6" - update-browserslist-db "^1.0.9" + caniuse-lite "^1.0.30001449" + electron-to-chromium "^1.4.284" + node-releases "^2.0.8" + update-browserslist-db "^1.0.10" bser@2.1.1: version "2.1.1" @@ -3939,15 +3820,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001400: - version "1.0.30001427" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001427.tgz#d3a749f74be7ae0671fbec3a4eea18576e8ad646" - integrity sha512-lfXQ73oB9c8DP5Suxaszm+Ta2sr/4tf8+381GkIm1MLj/YdLf+rEDyDSRCzeltuyTVGm+/s18gdZ0q+Wmp8VsQ== - -caniuse-lite@^1.0.30001426: - version "1.0.30001431" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz#e7c59bd1bc518fae03a4656be442ce6c4887a795" - integrity sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: + version "1.0.30001478" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001478.tgz#0ef8a1cf8b16be47a0f9fc4ecfc952232724b32a" + integrity sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw== case-sensitive-paths-webpack-plugin@^2.4.0: version "2.4.0" @@ -4008,9 +3884,9 @@ check-error@^1.0.2: integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== check-types@^11.1.1: - version "11.1.2" - resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.1.2.tgz#86a7c12bf5539f6324eb0e70ca8896c0e38f3e2f" - integrity sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ== + version "11.2.2" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.2.tgz#7afc0b6a860d686885062f2dba888ba5710335b4" + integrity sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA== "chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.2, chokidar@^3.5.3: version "3.5.3" @@ -4033,9 +3909,9 @@ chrome-trace-event@^1.0.2: integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== ci-info@^3.2.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.5.0.tgz#bfac2a29263de4c829d806b1ab478e35091e171f" - integrity sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw== + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== cjs-module-lexer@^1.0.0: version "1.2.2" @@ -4043,9 +3919,9 @@ cjs-module-lexer@^1.0.0: integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== clean-css@^5.2.2: - version "5.3.1" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.1.tgz#d0610b0b90d125196a2894d35366f734e5d7aa32" - integrity sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg== + version "5.3.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224" + integrity sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww== dependencies: source-map "~0.6.0" @@ -4156,6 +4032,11 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" @@ -4239,9 +4120,9 @@ content-disposition@0.5.4: safe-buffer "5.2.1" content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.9.0" @@ -4259,36 +4140,26 @@ cookie@0.5.0: integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== core-js-compat@^3.25.1: - version "3.26.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.26.0.tgz#94e2cf8ba3e63800c4956ea298a6473bc9d62b44" - integrity sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A== + version "3.30.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.30.0.tgz#99aa2789f6ed2debfa1df3232784126ee97f4d80" + integrity sha512-P5A2h/9mRYZFIAP+5Ab8ns6083IyVpSclU74UNvbGVQ8VM7n3n3/g2yF3AkKQ9NXz2O+ioxLbEWKnDtgsFamhg== dependencies: - browserslist "^4.21.4" + browserslist "^4.21.5" core-js-pure@^3.23.3: - version "3.26.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.26.1.tgz#653f4d7130c427820dcecd3168b594e8bb095a33" - integrity sha512-VVXcDpp/xJ21KdULRq/lXdLzQAtX7+37LzpyfFM973il0tWSsDEoyzG38G14AjTpK9VTfiNM9jnFauq/CpaWGQ== - -core-js-pure@^3.25.1: - version "3.26.0" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.26.0.tgz#7ad8a5dd7d910756f3124374b50026e23265ca9a" - integrity sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA== + version "3.30.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.30.0.tgz#41b6c42e5f363bd53d79999bd35093b17e42e1bf" + integrity sha512-+2KbMFGeBU0ln/csoPqTe0i/yfHbrd2EUhNMObsGtXMKS/RTtlkYyi+/3twLcevbgNR0yM/r0Psa3TEoQRpFMQ== core-js@3.6.5: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== -core-js@^3.19.2: - version "3.26.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.1.tgz#7a9816dabd9ee846c1c0fe0e8fcad68f3709134e" - integrity sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA== - -core-js@^3.4: - version "3.26.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.0.tgz#a516db0ed0811be10eac5d94f3b8463d03faccfe" - integrity sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw== +core-js@^3.19.2, core-js@^3.4: + version "3.30.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.30.0.tgz#64ac6f83bc7a49fd42807327051701d4b1478dea" + integrity sha512-hQotSSARoNh1mYPi9O2YaWeiq/cEB95kOrFb4NCrO4RIFt1qqNpKsaE+vy/L3oiqvND5cThqXzUU3r9F7Efztg== core-util-is@~1.0.0: version "1.0.3" @@ -4312,9 +4183,9 @@ cosmiconfig@^6.0.0: yaml "^1.7.2" cosmiconfig@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -4356,9 +4227,9 @@ css-blank-pseudo@^3.0.3: postcss-selector-parser "^6.0.9" css-declaration-sorter@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec" - integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w== + version "6.4.0" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz#630618adc21724484b3e9505bce812def44000ad" + integrity sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew== css-has-pseudo@^3.0.4: version "3.0.4" @@ -4368,12 +4239,12 @@ css-has-pseudo@^3.0.4: postcss-selector-parser "^6.0.9" css-loader@^6.5.1: - version "6.7.2" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.2.tgz#26bc22401b5921686a10fbeba75d124228302304" - integrity sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q== + version "6.7.3" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.3.tgz#1e8799f3ccc5874fdd55461af51137fcc5befbcd" + integrity sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ== dependencies: icss-utils "^5.1.0" - postcss "^8.4.18" + postcss "^8.4.19" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" @@ -4465,9 +4336,9 @@ css@^3.0.0: source-map-resolve "^0.6.0" cssdb@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.1.0.tgz#574f97235a83eb753a29f0b1f2cbacac0d628bb8" - integrity sha512-Sd99PrFgx28ez4GHu8yoQIufc/70h9oYowDf4EjeIKi8mac9whxRjhM3IaMr6EllP6KKKWtJrMfN6C7T9tIWvQ== + version "7.5.4" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.5.4.tgz#e34dafee5184d67634604e345e389ca79ac179ea" + integrity sha512-fGD+J6Jlq+aurfE1VDXlLS4Pt0VtNlu2+YgfGOdMxRyl/HQ9bDiHTwSck1Yz8A97Dt/82izSK6Bp/4nVqacOsg== cssesc@^3.0.0: version "3.0.0" @@ -4479,22 +4350,22 @@ cssfontparser@^1.2.1: resolved "https://registry.yarnpkg.com/cssfontparser/-/cssfontparser-1.2.1.tgz#f4022fc8f9700c68029d542084afbaf425a3f3e3" integrity sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg== -cssnano-preset-default@^5.2.13: - version "5.2.13" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz#e7353b0c57975d1bdd97ac96e68e5c1b8c68e990" - integrity sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ== +cssnano-preset-default@^5.2.14: + version "5.2.14" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz#309def4f7b7e16d71ab2438052093330d9ab45d8" + integrity sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A== dependencies: css-declaration-sorter "^6.3.1" cssnano-utils "^3.1.0" postcss-calc "^8.2.3" - postcss-colormin "^5.3.0" + postcss-colormin "^5.3.1" postcss-convert-values "^5.1.3" postcss-discard-comments "^5.1.2" postcss-discard-duplicates "^5.1.0" postcss-discard-empty "^5.1.1" postcss-discard-overridden "^5.1.0" postcss-merge-longhand "^5.1.7" - postcss-merge-rules "^5.1.3" + postcss-merge-rules "^5.1.4" postcss-minify-font-values "^5.1.0" postcss-minify-gradients "^5.1.1" postcss-minify-params "^5.1.4" @@ -4509,7 +4380,7 @@ cssnano-preset-default@^5.2.13: postcss-normalize-url "^5.1.0" postcss-normalize-whitespace "^5.1.1" postcss-ordered-values "^5.1.3" - postcss-reduce-initial "^5.1.1" + postcss-reduce-initial "^5.1.2" postcss-reduce-transforms "^5.1.0" postcss-svgo "^5.1.0" postcss-unique-selectors "^5.1.1" @@ -4520,11 +4391,11 @@ cssnano-utils@^3.1.0: integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA== cssnano@^5.0.6: - version "5.1.14" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.14.tgz#07b0af6da73641276fe5a6d45757702ebae2eb05" - integrity sha512-Oou7ihiTocbKqi0J1bB+TRJIQX5RMR3JghA8hcWSw9mjBLQ5Y3RWqEDoYG3sRNlAbCIXpqMoZGbq5KDR3vdzgw== + version "5.1.15" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.15.tgz#ded66b5480d5127fcb44dac12ea5a983755136bf" + integrity sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw== dependencies: - cssnano-preset-default "^5.2.13" + cssnano-preset-default "^5.2.14" lilconfig "^2.0.3" yaml "^1.10.2" @@ -4553,9 +4424,9 @@ cssstyle@^2.3.0: cssom "~0.3.6" csstype@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" - integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== damerau-levenshtein@^1.0.8: version "1.0.8" @@ -4571,7 +4442,7 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -debug@2.6.9, debug@^2.6.0, debug@^2.6.9: +debug@2.6.9, debug@^2.6.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -4600,9 +4471,9 @@ debug@~3.1.0: ms "2.0.0" decimal.js@^10.2.1: - version "10.4.2" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.2.tgz#0341651d1d997d86065a2ce3a441fbd0d8e8b98e" - integrity sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA== + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== decode-uri-component@^0.2.0: version "0.2.2" @@ -4622,25 +4493,27 @@ deep-eql@^3.0.1: type-detect "^4.0.0" deep-equal@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.5.tgz#55cd2fe326d83f9cbf7261ef0e060b3f724c5cb9" - integrity sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw== + version "2.2.0" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.0.tgz#5caeace9c781028b9ff459f33b779346637c43e6" + integrity sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw== dependencies: - call-bind "^1.0.0" - es-get-iterator "^1.1.1" - get-intrinsic "^1.0.1" - is-arguments "^1.0.4" - is-date-object "^1.0.2" - is-regex "^1.1.1" + call-bind "^1.0.2" + es-get-iterator "^1.1.2" + get-intrinsic "^1.1.3" + is-arguments "^1.1.1" + is-array-buffer "^3.0.1" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" isarray "^2.0.5" - object-is "^1.1.4" + object-is "^1.1.5" object-keys "^1.1.1" - object.assign "^4.1.2" - regexp.prototype.flags "^1.3.0" - side-channel "^1.0.3" - which-boxed-primitive "^1.0.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" which-collection "^1.0.1" - which-typed-array "^1.1.2" + which-typed-array "^1.1.9" deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" @@ -4648,9 +4521,9 @@ deep-is@^0.1.3, deep-is@~0.1.3: integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== default-gateway@^6.0.3: version "6.0.3" @@ -4665,18 +4538,13 @@ define-lazy-prop@^2.0.0: integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== define-properties@^1.1.3, define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== dependencies: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -defined@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" - integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -4702,6 +4570,11 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" @@ -4715,15 +4588,6 @@ detect-port-alt@^1.1.6: address "^1.0.1" debug "^2.6.0" -detective@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034" - integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw== - dependencies: - acorn-node "^1.8.2" - defined "^1.0.0" - minimist "^1.2.6" - didyoumean@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" @@ -4734,10 +4598,10 @@ diff-sequences@^27.5.1: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== -diff-sequences@^29.2.0: - version "29.2.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.2.0.tgz#4c55b5b40706c7b5d2c5c75999a50c56d214e8f6" - integrity sha512-413SY5JpYeSBZxmenGEmCVQ8mCgtFJF0w9PROdaS6z987XC2Pd2GOKqOITLtMftmyFZqgtCOb/QA7/Z3ZXfzIw== +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== dir-glob@^3.0.1: version "3.0.1" @@ -4757,9 +4621,9 @@ dns-equal@^1.0.0: integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== dns-packet@^5.2.2: - version "5.4.0" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b" - integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g== + version "5.5.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.5.0.tgz#f59cbf3396c130957c56a6ad5fd3959ccdc30065" + integrity sha512-USawdAUzRkV6xrqTjiAEp6M9YagZEzWcSUaZTcIFAiyQWW1SoI6KyId8y2+/71wbgHKQAKd+iupLv4YvEwYWvA== dependencies: "@leichtgewicht/ip-codec" "^2.0.1" @@ -4778,9 +4642,9 @@ doctrine@^3.0.0: esutils "^2.0.2" dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9: - version "0.5.14" - resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56" - integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg== + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== dom-converter@^0.2.0: version "0.2.0" @@ -4898,16 +4762,16 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== ejs@^3.1.6: - version "3.1.8" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b" - integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ== + version "3.1.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" + integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== dependencies: jake "^10.8.5" -electron-to-chromium@^1.4.251: - version "1.4.284" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" - integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== +electron-to-chromium@^1.4.284: + version "1.4.359" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.359.tgz#5c4d13cb08032469fcd6bd36457915caa211356b" + integrity sha512-OoVcngKCIuNXtZnsYoqlCvr0Cf3NIPzDIgwUfI9bdTFjXCrr79lI0kwQstLPZ7WhCezLlGksZk/BFAzoXC7GDw== emittery@^0.10.2: version "0.10.2" @@ -4968,9 +4832,9 @@ engine.io-parser@~2.2.0: has-binary2 "~1.0.2" enhanced-resolve@^5.10.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6" - integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== + version "5.12.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" + integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -5001,60 +4865,80 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.3.4" -es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5, es-abstract@^1.20.0, es-abstract@^1.20.1, es-abstract@^1.20.4: - version "1.20.4" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861" - integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA== +es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== dependencies: + array-buffer-byte-length "^1.0.0" + available-typed-arrays "^1.0.5" call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function-bind "^1.1.1" function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.0" get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" has "^1.0.3" has-property-descriptors "^1.0.0" + has-proto "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" is-shared-array-buffer "^1.0.2" is-string "^1.0.7" + is-typed-array "^1.1.10" is-weakref "^1.0.2" - object-inspect "^1.12.2" + object-inspect "^1.12.3" object-keys "^1.1.1" object.assign "^4.1.4" regexp.prototype.flags "^1.4.3" safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.5" - string.prototype.trimstart "^1.0.5" + string.prototype.trim "^1.2.7" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-length "^1.0.4" unbox-primitive "^1.0.2" + which-typed-array "^1.1.9" es-array-method-boxes-properly@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== -es-get-iterator@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" - integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== +es-get-iterator@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.1.0" - has-symbols "^1.0.1" - is-arguments "^1.1.0" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" is-map "^2.0.2" is-set "^2.0.2" - is-string "^1.0.5" + is-string "^1.0.7" isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" es-module-lexer@^0.9.0: version "0.9.3" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + es-shim-unscopables@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" @@ -5133,15 +5017,16 @@ eslint-config-react-app@^7.0.1: eslint-plugin-react-hooks "^4.3.0" eslint-plugin-testing-library "^5.0.1" -eslint-import-resolver-node@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" - integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== +eslint-import-resolver-node@^0.3.7: + version "0.3.7" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" + integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== dependencies: debug "^3.2.7" - resolve "^1.20.0" + is-core-module "^2.11.0" + resolve "^1.22.1" -eslint-module-utils@^2.7.3: +eslint-module-utils@^2.7.4: version "2.7.4" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== @@ -5157,22 +5042,24 @@ eslint-plugin-flowtype@^8.0.3: string-natural-compare "^3.0.1" eslint-plugin-import@^2.25.3: - version "2.26.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" - integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== + version "2.27.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" + integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== dependencies: - array-includes "^3.1.4" - array.prototype.flat "^1.2.5" - debug "^2.6.9" + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + array.prototype.flatmap "^1.3.1" + debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.3" + eslint-import-resolver-node "^0.3.7" + eslint-module-utils "^2.7.4" has "^1.0.3" - is-core-module "^2.8.1" + is-core-module "^2.11.0" is-glob "^4.0.3" minimatch "^3.1.2" - object.values "^1.1.5" - resolve "^1.22.0" + object.values "^1.1.6" + resolve "^1.22.1" + semver "^6.3.0" tsconfig-paths "^3.14.1" eslint-plugin-jest@^25.3.0: @@ -5183,22 +5070,25 @@ eslint-plugin-jest@^25.3.0: "@typescript-eslint/experimental-utils" "^5.0.0" eslint-plugin-jsx-a11y@^6.5.1: - version "6.6.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz#93736fc91b83fdc38cc8d115deedfc3091aef1ff" - integrity sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q== + version "6.7.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" + integrity sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA== dependencies: - "@babel/runtime" "^7.18.9" - aria-query "^4.2.2" - array-includes "^3.1.5" + "@babel/runtime" "^7.20.7" + aria-query "^5.1.3" + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" ast-types-flow "^0.0.7" - axe-core "^4.4.3" - axobject-query "^2.2.0" + axe-core "^4.6.2" + axobject-query "^3.1.1" damerau-levenshtein "^1.0.8" emoji-regex "^9.2.2" has "^1.0.3" - jsx-ast-utils "^3.3.2" - language-tags "^1.0.5" + jsx-ast-utils "^3.3.3" + language-tags "=1.0.5" minimatch "^3.1.2" + object.entries "^1.1.6" + object.fromentries "^2.0.6" semver "^6.3.0" eslint-plugin-prettier@3.3.1: @@ -5214,9 +5104,9 @@ eslint-plugin-react-hooks@^4.3.0: integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== eslint-plugin-react@^7.27.1: - version "7.31.11" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz#011521d2b16dcf95795df688a4770b4eaab364c8" - integrity sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw== + version "7.32.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" + integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== dependencies: array-includes "^3.1.6" array.prototype.flatmap "^1.3.1" @@ -5230,16 +5120,16 @@ eslint-plugin-react@^7.27.1: object.hasown "^1.1.2" object.values "^1.1.6" prop-types "^15.8.1" - resolve "^2.0.0-next.3" + resolve "^2.0.0-next.4" semver "^6.3.0" string.prototype.matchall "^4.0.8" eslint-plugin-testing-library@^5.0.1: - version "5.9.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz#12e4bd34c48683ee98af4df2e3318ec9f51dcf8a" - integrity sha512-6BQp3tmb79jLLasPHJmy8DnxREe+2Pgf7L+7o09TSWPfdqqtQfRZmZNetr5mOs3yqZk/MRNxpN3RUpJe0wB4LQ== + version "5.10.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.2.tgz#12f231ad9b52b6aef45c801fd00aa129a932e0c2" + integrity sha512-f1DmDWcz5SDM+IpCkEX0lbFqrrTs8HRsEElzDEqN/EBI0hpRj8Cns5+IVANXswE8/LeybIJqPAOQIFu2j5Y5sw== dependencies: - "@typescript-eslint/utils" "^5.13.0" + "@typescript-eslint/utils" "^5.43.0" eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" @@ -5264,13 +5154,6 @@ eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" @@ -5281,10 +5164,10 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc" + integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== eslint-webpack-plugin@^3.1.1: version "3.2.0" @@ -5344,12 +5227,15 @@ eslint@^7.32.0: v8-compile-cache "^2.0.3" eslint@^8.3.0: - version "8.28.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.28.0.tgz#81a680732634677cc890134bcdd9fdfea8e63d6e" - integrity sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ== + version "8.38.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.38.0.tgz#a62c6f36e548a5574dd35728ac3c6209bd1e2f1a" + integrity sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg== dependencies: - "@eslint/eslintrc" "^1.3.3" - "@humanwhocodes/config-array" "^0.11.6" + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.2" + "@eslint/js" "8.38.0" + "@humanwhocodes/config-array" "^0.11.8" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" ajv "^6.10.0" @@ -5359,16 +5245,15 @@ eslint@^8.3.0: doctrine "^3.0.0" escape-string-regexp "^4.0.0" eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.4.0" - esquery "^1.4.0" + eslint-visitor-keys "^3.4.0" + espree "^9.5.1" + esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.15.0" + globals "^13.19.0" grapheme-splitter "^1.0.4" ignore "^5.2.0" import-fresh "^3.0.0" @@ -5383,7 +5268,6 @@ eslint@^8.3.0: minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" - regexpp "^3.2.0" strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" @@ -5397,24 +5281,24 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== +espree@^9.5.1: + version "9.5.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4" + integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg== dependencies: acorn "^8.8.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.4.0, esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" @@ -5491,15 +5375,15 @@ expect@^27.5.1: jest-message-util "^27.5.1" expect@^29.0.0: - version "29.2.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.2.2.tgz#ba2dd0d7e818727710324a6e7f13dd0e6d086106" - integrity sha512-hE09QerxZ5wXiOhqkXy5d2G9ar+EqOyifnCXCpMNu+vZ6DG9TJ6CO2c2kPDSLqERTTWrO7OZj8EkYHQqSd78Yw== + version "29.5.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" + integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== dependencies: - "@jest/expect-utils" "^29.2.2" - jest-get-type "^29.2.0" - jest-matcher-utils "^29.2.2" - jest-message-util "^29.2.1" - jest-util "^29.2.1" + "@jest/expect-utils" "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" express@^4.17.3: version "4.18.2" @@ -5577,9 +5461,9 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== dependencies: reusify "^1.0.4" @@ -5729,9 +5613,9 @@ for-each@^0.3.3: is-callable "^1.1.3" fork-ts-checker-webpack-plugin@^6.5.0: - version "6.5.2" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz#4f67183f2f9eb8ba7df7177ce3cf3e75cdafb340" - integrity sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA== + version "6.5.3" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz#eda2eff6e22476a2688d10661688c47f611b37f3" + integrity sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ== dependencies: "@babel/code-frame" "^7.8.3" "@types/json-schema" "^7.0.5" @@ -5845,15 +5729,20 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" - integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== dependencies: function-bind "^1.1.1" has "^1.0.3" has-symbols "^1.0.3" +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" @@ -5896,6 +5785,18 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -5929,19 +5830,19 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.15.0: - version "13.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.18.0.tgz#fb224daeeb2bb7d254cd2c640f003528b8d0c1dc" - integrity sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A== +globals@^13.19.0, globals@^13.6.0, globals@^13.9.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== dependencies: type-fest "^0.20.2" -globals@^13.6.0, globals@^13.9.0: - version "13.17.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" - integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== dependencies: - type-fest "^0.20.2" + define-properties "^1.1.3" globby@^11.0.4, globby@^11.1.0: version "11.1.0" @@ -5960,10 +5861,17 @@ glur@^1.1.2: resolved "https://registry.yarnpkg.com/glur/-/glur-1.1.2.tgz#f20ea36db103bfc292343921f1f91e83c3467689" integrity sha512-l+8esYHTKOx2G/Aao4lEQ0bnHWg4fWtJbVoZZT9Knxi01pB8C80BR85nONLFwkkQoFRCmXY+BUcGZN3yZ2QsRA== +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== grapheme-splitter@^1.0.4: version "1.0.4" @@ -6021,6 +5929,11 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" @@ -6271,9 +6184,9 @@ ignore@^4.0.6: integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== image-blob-reduce@3.0.1: version "3.0.1" @@ -6288,14 +6201,14 @@ immediate@~3.0.5: integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== immer@^9.0.7: - version "9.0.16" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.16.tgz#8e7caab80118c2b54b37ad43e05758cdefad0198" - integrity sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ== + version "9.0.21" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" + integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== immutable@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" - integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== + version "4.3.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be" + integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg== import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: version "3.3.0" @@ -6351,15 +6264,22 @@ ini@^1.3.5: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== +internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== dependencies: - get-intrinsic "^1.1.0" + get-intrinsic "^1.2.0" has "^1.0.3" side-channel "^1.0.4" +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -6370,7 +6290,7 @@ ipaddr.js@^2.0.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== -is-arguments@^1.0.4, is-arguments@^1.1.0: +is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== @@ -6378,6 +6298,15 @@ is-arguments@^1.0.4, is-arguments@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -6410,14 +6339,14 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.8.1, is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== +is-core-module@^2.11.0, is-core-module@^2.9.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" + integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ== dependencies: has "^1.0.3" -is-date-object@^1.0.1, is-date-object@^1.0.2: +is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== @@ -6503,7 +6432,7 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-regex@^1.1.1, is-regex@^1.1.4: +is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -6552,15 +6481,15 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.9.tgz#246d77d2871e7d9f5aeb1d54b9f52c71329ece67" - integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== +is-typed-array@^1.1.10, is-typed-array@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== dependencies: available-typed-arrays "^1.0.5" call-bind "^1.0.2" - es-abstract "^1.20.0" for-each "^0.3.3" + gopd "^1.0.1" has-tostringtag "^1.0.0" is-typedarray@^1.0.0: @@ -6767,15 +6696,15 @@ jest-diff@^27.0.0, jest-diff@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" -jest-diff@^29.2.1: - version "29.2.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.2.1.tgz#027e42f5a18b693fb2e88f81b0ccab533c08faee" - integrity sha512-gfh/SMNlQmP3MOUgdzxPOd4XETDJifADpT937fN1iUGz+9DgOu2eUPHH25JDkLVcLwwqxv3GzVyK4VBUr9fjfA== +jest-diff@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63" + integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== dependencies: chalk "^4.0.0" - diff-sequences "^29.2.0" - jest-get-type "^29.2.0" - pretty-format "^29.2.1" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" jest-docblock@^27.5.1: version "27.5.1" @@ -6825,10 +6754,10 @@ jest-get-type@^27.5.1: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== -jest-get-type@^29.2.0: - version "29.2.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.2.0.tgz#726646f927ef61d583a3b3adb1ab13f3a5036408" - integrity sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA== +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== jest-haste-map@^27.5.1: version "27.5.1" @@ -6891,15 +6820,15 @@ jest-matcher-utils@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" -jest-matcher-utils@^29.2.2: - version "29.2.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.2.2.tgz#9202f8e8d3a54733266784ce7763e9a08688269c" - integrity sha512-4DkJ1sDPT+UX2MR7Y3od6KtvRi9Im1ZGLGgdLFLm4lPexbTaCgJW5NN3IOXlQHF7NSHY/VHhflQ+WoKtD/vyCw== +jest-matcher-utils@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz#d957af7f8c0692c5453666705621ad4abc2c59c5" + integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== dependencies: chalk "^4.0.0" - jest-diff "^29.2.1" - jest-get-type "^29.2.0" - pretty-format "^29.2.1" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" jest-message-util@^27.5.1: version "27.5.1" @@ -6931,18 +6860,18 @@ jest-message-util@^28.1.3: slash "^3.0.0" stack-utils "^2.0.3" -jest-message-util@^29.2.1: - version "29.2.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.2.1.tgz#3a51357fbbe0cc34236f17a90d772746cf8d9193" - integrity sha512-Dx5nEjw9V8C1/Yj10S/8ivA8F439VS8vTq1L7hEgwHFn9ovSKNpYW/kwNh7UglaEgXO42XxzKJB+2x0nSglFVw== +jest-message-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e" + integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.2.1" + "@jest/types" "^29.5.0" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^29.2.1" + pretty-format "^29.5.0" slash "^3.0.0" stack-utils "^2.0.3" @@ -6955,9 +6884,9 @@ jest-mock@^27.5.1: "@types/node" "*" jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== jest-regex-util@^27.5.1: version "27.5.1" @@ -7109,12 +7038,12 @@ jest-util@^28.1.3: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-util@^29.2.1: - version "29.2.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.2.1.tgz#f26872ba0dc8cbefaba32c34f98935f6cf5fc747" - integrity sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g== +jest-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" + integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== dependencies: - "@jest/types" "^29.2.1" + "@jest/types" "^29.5.0" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" @@ -7209,15 +7138,20 @@ jest@^27.4.3: import-local "^3.0.2" jest-cli "^27.5.1" +jiti@^1.17.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd" + integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg== + jotai@1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/jotai/-/jotai-1.6.4.tgz#4d9904362c53c4293d32e21fb358d3de34b82912" integrity sha512-XC0ExLhdE6FEBdIjKTe6kMlHaAUV/QiwN7vZond76gNr/WdcdonJOEW79+5t8u38sR41bJXi26B1dRi7cCRz9A== js-sdsl@^4.1.4: - version "4.1.5" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.5.tgz#1ff1645e6b4d1b028cd3f862db88c9d887f26e2a" - integrity sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q== + version "4.4.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430" + integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg== "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" @@ -7307,17 +7241,17 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json5@^1.0.1: +json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" -json5@^2.1.2, json5@^2.2.0, json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +json5@^2.1.2, json5@^2.2.0, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== jsonfile@^6.0.1: version "6.1.0" @@ -7333,7 +7267,7 @@ jsonpointer@^5.0.0: resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.2: +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== @@ -7352,22 +7286,30 @@ kleur@^3.0.3: integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== klona@^2.0.4, klona@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" - integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== + version "2.0.6" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" + integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== language-subtag-registry@~0.3.2: version "0.3.22" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== -language-tags@^1.0.5: +language-tags@=1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== dependencies: language-subtag-registry "~0.3.2" +launch-editor@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" + integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== + dependencies: + picocolors "^1.0.0" + shell-quote "^1.7.3" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -7402,9 +7344,9 @@ lilconfig@2.0.4: integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== lilconfig@^2.0.3, lilconfig@^2.0.5, lilconfig@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" - integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== lines-and-columns@^1.1.6: version "1.2.4" @@ -7450,7 +7392,7 @@ loader-runner@^4.2.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== -loader-utils@^2.0.0, loader-utils@^2.0.3: +loader-utils@^2.0.0, loader-utils@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== @@ -7554,11 +7496,11 @@ long@^4.0.0: integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== long@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61" - integrity sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w== + version "5.2.1" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f" + integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A== -loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -7566,9 +7508,9 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: js-tokens "^3.0.0 || ^4.0.0" loupe@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" - integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== + version "2.3.6" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" + integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== dependencies: get-func-name "^2.0.0" @@ -7579,6 +7521,13 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -7587,9 +7536,9 @@ lru-cache@^6.0.0: yallist "^4.0.0" lz-string@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" - integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== magic-string@^0.25.0, magic-string@^0.25.7: version "0.25.9" @@ -7628,9 +7577,9 @@ media-typer@0.3.0: integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== memfs@^3.1.2, memfs@^3.4.3: - version "3.4.11" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.11.tgz#3a34837ade675825d805a2c135e88cefe5e53aaf" - integrity sha512-GvsCITGAyDCxxsJ+X6prJexFQEhOCJaIlUbsAvjzSI5o5O7j2dle3jWvz5Z5aOdpOxW6ol3vI1+0ut+641F1+w== + version "3.5.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.5.0.tgz#9da86405fca0a539addafd37dbd452344fd1c0bd" + integrity sha512-yK6o8xVJlQerz57kvPROwTMgx5WtGwC2ZxDtOUsnGl49rHjYkfQoPNZPCKH73VdLE1BwBu/+Fx/NL8NYMUw2aA== dependencies: fs-monkey "^1.0.3" @@ -7690,9 +7639,9 @@ min-indent@^1.0.0: integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== mini-css-extract-plugin@^2.4.5: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz#d7d9ba0c5b596d155e36e2b174082fc7f010dd64" - integrity sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw== + version "2.7.5" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz#afbb344977659ec0f1f6e050c7aea456b121cfc5" + integrity sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ== dependencies: schema-utils "^4.0.0" @@ -7709,16 +7658,16 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: brace-expansion "^1.1.7" minimatch@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" - integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: brace-expansion "^2.0.1" minimist@^1.2.0, minimist@^1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== mkdirp@^0.5.6, mkdirp@~0.5.1: version "0.5.6" @@ -7765,15 +7714,24 @@ multimath@^2.0.0: glur "^1.1.2" object-assign "^4.1.1" +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nanoid@3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== nanoid@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== natural-compare-lite@^1.4.0: version "1.4.0" @@ -7818,10 +7776,10 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== +node-releases@^2.0.8: + version "2.0.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" + integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -7860,11 +7818,11 @@ nth-check@^2.0.1: boolbase "^1.0.0" nwsapi@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" - integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== + version "2.2.3" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.3.tgz#00e04dfd5a4a751e5ec2fecdc75dfd2f0db820fa" + integrity sha512-jscxIO4/VKScHlbmFBdV1Z6LXnLO+ZR4VMtypudUdfwtKxUN3TQcNFIHLwKtrUbDyHN4/GycY9+oRGZ2XMXYPw== -object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -7874,12 +7832,12 @@ object-hash@^3.0.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== -object-inspect@^1.12.0, object-inspect@^1.12.2, object-inspect@^1.9.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-inspect@^1.12.0, object-inspect@^1.12.3, object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== -object-is@^1.1.4: +object-is@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== @@ -7892,7 +7850,7 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.2, object.assign@^4.1.3, object.assign@^4.1.4: +object.assign@^4.1.3, object.assign@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== @@ -7921,14 +7879,14 @@ object.fromentries@^2.0.6: es-abstract "^1.20.4" object.getownpropertydescriptors@^2.1.0: - version "2.1.4" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz#7965e6437a57278b587383831a9b829455a4bc37" - integrity sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ== + version "2.1.5" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz#db5a9002489b64eef903df81d6623c07e5b4b4d3" + integrity sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw== dependencies: - array.prototype.reduce "^1.0.4" + array.prototype.reduce "^1.0.5" call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.20.1" + es-abstract "^1.20.4" object.hasown@^1.1.2: version "1.1.2" @@ -7938,16 +7896,7 @@ object.hasown@^1.1.2: define-properties "^1.1.4" es-abstract "^1.20.4" -object.values@^1.1.0, object.values@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -object.values@^1.1.6: +object.values@^1.1.0, object.values@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== @@ -7993,9 +7942,9 @@ open-color@1.9.1: integrity sha512-vCseG/EQ6/RcvxhUcGJiHViOgrtz4x0XbZepXvKik66TMGkvbmjeJrKFyBEx6daG5rNyyd14zYXhz0hZVwQFOw== open@^8.0.9, open@^8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" - integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== dependencies: define-lazy-prop "^2.0.0" is-docker "^2.1.1" @@ -8239,7 +8188,7 @@ pify@^2.3.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== -pirates@^4.0.4: +pirates@^4.0.1, pirates@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== @@ -8348,12 +8297,12 @@ postcss-color-rebeccapurple@^7.1.1: dependencies: postcss-value-parser "^4.2.0" -postcss-colormin@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a" - integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg== +postcss-colormin@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz#86c27c26ed6ba00d96c79e08f3ffb418d1d1988f" + integrity sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.4" caniuse-api "^3.0.0" colord "^2.9.1" postcss-value-parser "^4.2.0" @@ -8374,9 +8323,9 @@ postcss-custom-media@^8.0.2: postcss-value-parser "^4.2.0" postcss-custom-properties@^12.1.10: - version "12.1.10" - resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-12.1.10.tgz#624517179fd4cf50078a7a60f628d5782e7d4903" - integrity sha512-U3BHdgrYhCrwTVcByFHs9EOBoqcKq4Lf3kXwbTi4hhq0qWhl/pDWq2THbv/ICX/Fl9KqeHBb8OVrTf2OaYF07A== + version "12.1.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz#d14bb9b3989ac4d40aaa0e110b43be67ac7845cf" + integrity sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ== dependencies: postcss-value-parser "^4.2.0" @@ -8480,9 +8429,9 @@ postcss-initial@^4.0.1: integrity sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ== postcss-js@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" - integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ== + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== dependencies: camelcase-css "^2.0.1" @@ -8529,10 +8478,10 @@ postcss-merge-longhand@^5.1.7: postcss-value-parser "^4.2.0" stylehacks "^5.1.1" -postcss-merge-rules@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz#8f97679e67cc8d08677a6519afca41edf2220894" - integrity sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA== +postcss-merge-rules@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz#2f26fa5cacb75b1402e213789f6766ae5e40313c" + integrity sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g== dependencies: browserslist "^4.21.4" caniuse-api "^3.0.0" @@ -8687,9 +8636,9 @@ postcss-normalize@^10.0.1: sanitize.css "*" postcss-opacity-percentage@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz#bd698bb3670a0a27f6d657cc16744b3ebf3b1145" - integrity sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w== + version "1.1.3" + resolved "https://registry.yarnpkg.com/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz#5b89b35551a556e20c5d23eb5260fbfcf5245da6" + integrity sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A== postcss-ordered-values@^5.1.3: version "5.1.3" @@ -8780,10 +8729,10 @@ postcss-pseudo-class-any-link@^7.1.6: dependencies: postcss-selector-parser "^6.0.10" -postcss-reduce-initial@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz#c18b7dfb88aee24b1f8e4936541c29adbd35224e" - integrity sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w== +postcss-reduce-initial@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz#798cd77b3e033eae7105c18c9d371d989e1382d6" + integrity sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg== dependencies: browserslist "^4.21.4" caniuse-api "^3.0.0" @@ -8807,10 +8756,10 @@ postcss-selector-not@^6.0.1: dependencies: postcss-selector-parser "^6.0.10" -postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: - version "6.0.10" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" - integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== +postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: + version "6.0.11" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" + integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -8843,10 +8792,10 @@ postcss@^7.0.35: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.3.5, postcss@^8.4.18, postcss@^8.4.4: - version "8.4.19" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc" - integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== +postcss@^8.0.9, postcss@^8.3.5, postcss@^8.4.19, postcss@^8.4.4: + version "8.4.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" + integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== dependencies: nanoid "^3.3.4" picocolors "^1.0.0" @@ -8906,12 +8855,12 @@ pretty-format@^28.1.3: ansi-styles "^5.0.0" react-is "^18.0.0" -pretty-format@^29.0.0, pretty-format@^29.2.1: - version "29.2.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.2.1.tgz#86e7748fe8bbc96a6a4e04fa99172630907a9611" - integrity sha512-Y41Sa4aLCtKAXvwuIpTvcFBkyeYp2gdFWzXGA+ZNES3VwURIB165XO/z7CjETwzCCS53MjW/rLMyyqEnTtaOfA== +pretty-format@^29.0.0, pretty-format@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" + integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== dependencies: - "@jest/schemas" "^29.0.0" + "@jest/schemas" "^29.4.3" ansi-styles "^5.0.0" react-is "^18.0.0" @@ -8974,9 +8923,9 @@ protobufjs@^6.8.6: long "^4.0.0" protobufjs@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.2.tgz#a0cf6aeaf82f5625bffcf5a38b7cd2a7de05890c" - integrity sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ== + version "7.2.3" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2" + integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -9005,9 +8954,9 @@ psl@^1.1.33: integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== pwacompat@2.0.17: version "2.0.17" @@ -9019,13 +8968,20 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@6.11.0, qs@^6.4.0: +qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" +qs@^6.4.0: + version "6.11.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.1.tgz#6c29dff97f0c0060765911ba65cbc9764186109f" + integrity sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ== + dependencies: + side-channel "^1.0.4" + querystringify@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" @@ -9145,6 +9101,25 @@ react-refresh@^0.11.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== +react-remove-scroll-bar@^2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9" + integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A== + dependencies: + react-style-singleton "^2.2.1" + tslib "^2.0.0" + +react-remove-scroll@2.5.5: + version "2.5.5" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77" + integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw== + dependencies: + react-remove-scroll-bar "^2.3.3" + react-style-singleton "^2.2.1" + tslib "^2.1.0" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" + react-scripts@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003" @@ -9200,6 +9175,15 @@ react-scripts@5.0.1: optionalDependencies: fsevents "^2.3.2" +react-style-singleton@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4" + integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^2.0.0" + react@18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" @@ -9215,9 +9199,9 @@ read-cache@^1.0.0: pify "^2.3.0" readable-stream@^2.0.1: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -9228,9 +9212,9 @@ readable-stream@^2.0.1: util-deprecate "~1.0.1" readable-stream@^3.0.6: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" @@ -9280,20 +9264,15 @@ regenerate@^1.4.2: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.13.10: - version "0.13.10" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee" - integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw== - regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.9: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regenerator-transform@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" - integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== +regenerator-transform@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" + integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== dependencies: "@babel/runtime" "^7.8.4" @@ -9302,7 +9281,7 @@ regex-parser@^2.2.11: resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== -regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.4.3: +regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== @@ -9311,27 +9290,22 @@ regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" -regexpp@^3.1.0, regexpp@^3.2.0: +regexpp@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -regexpu-core@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.1.tgz#a69c26f324c1e962e9ffd0b88b055caba8089139" - integrity sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ== +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== dependencies: + "@babel/regjsgen" "^0.8.0" regenerate "^1.4.2" regenerate-unicode-properties "^10.1.0" - regjsgen "^0.7.1" regjsparser "^0.9.1" unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" - -regjsgen@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.7.1.tgz#ee5ef30e18d3f09b7c369b76e7c2373ed25546f6" - integrity sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA== + unicode-match-property-value-ecmascript "^2.1.0" regjsparser@^0.9.1: version "0.9.1" @@ -9400,20 +9374,20 @@ resolve-url-loader@^4.0.0: source-map "0.6.1" resolve.exports@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" - integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + version "1.1.1" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" + integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== -resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== +resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.11.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.3: +resolve@^2.0.0-next.4: version "2.0.0-next.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== @@ -9493,9 +9467,9 @@ run-parallel@^1.1.9: queue-microtask "^1.2.2" rxjs@^7.5.5: - version "7.5.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39" - integrity sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA== + version "7.8.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" + integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== dependencies: tslib "^2.1.0" @@ -9629,9 +9603,9 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== semver@^7.2.1, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + version "7.4.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.4.0.tgz#8481c92feffc531ab1e012a8ffc15bdd3a0f4318" + integrity sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw== dependencies: lru-cache "^6.0.0" @@ -9661,10 +9635,10 @@ serialize-javascript@^4.0.0: dependencies: randombytes "^2.1.0" -serialize-javascript@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== +serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== dependencies: randombytes "^2.1.0" @@ -9714,11 +9688,11 @@ shebang-regex@^3.0.0: integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.7.3: - version "1.7.4" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.4.tgz#33fe15dee71ab2a81fcbd3a52106c5cfb9fb75d8" - integrity sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw== + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -side-channel@^1.0.3, side-channel@^1.0.4: +side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== @@ -9904,9 +9878,9 @@ stable@^0.1.8: integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== stack-utils@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== dependencies: escape-string-regexp "^2.0.0" @@ -9925,6 +9899,13 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -9983,23 +9964,32 @@ string.prototype.matchall@^4.0.6, string.prototype.matchall@^4.0.8: regexp.prototype.flags "^1.4.3" side-channel "^1.0.4" -string.prototype.trimend@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" - integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" -string.prototype.trimstart@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" - integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" - es-abstract "^1.19.5" + es-abstract "^1.20.4" + +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" string_decoder@^1.1.1: version "1.3.0" @@ -10071,9 +10061,9 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== style-loader@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" - integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== + version "3.3.2" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.2.tgz#eaebca714d9e462c19aa1e3599057bc363924899" + integrity sha512-RHs/vcrKdQK8wZliteNK4NKzxvLBzpuHMqYmUVWeKa6MkaIQ97ZTOS0b+zapZhy6GcrgWnvWYCMHRirC3FsUmw== stylehacks@^5.1.1: version "5.1.1" @@ -10083,6 +10073,19 @@ stylehacks@^5.1.1: browserslist "^4.21.4" postcss-selector-parser "^6.0.4" +sucrase@^3.29.0: + version "3.32.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.32.0.tgz#c4a95e0f1e18b6847127258a75cf360bc568d4a7" + integrity sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "7.1.6" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -10105,9 +10108,9 @@ supports-color@^8.0.0: has-flag "^4.0.0" supports-color@^9.2.1: - version "9.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.3.tgz#a6e2c97fc20c80abecd69e50aebe4783ff77d45a" - integrity sha512-aszYUX/DVK/ed5rFLb/dDinVJrQjG/vmU433wtqVSD800rYsJNWxh2R3USV90aLSU+UsyQkbNeffVLzc6B6foA== + version "9.3.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.3.1.tgz#34e4ad3c71c9a39dae3254ecc46c9b74e89e15a6" + integrity sha512-knBY82pjmnIzK3NifMo3RxEIRD9E0kIzV4BKcyTZ9+9kWgLMxd4PrsTSMoFQUabgRBbF8KOLRDCyKgNV+iK44Q== supports-hyperlinks@^2.0.0: version "2.3.0" @@ -10165,9 +10168,9 @@ symbol-tree@^3.2.4: integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== table@^6.0.9: - version "6.8.0" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" - integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== + version "6.8.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -10176,33 +10179,34 @@ table@^6.0.9: strip-ansi "^6.0.1" tailwindcss@^3.0.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.2.4.tgz#afe3477e7a19f3ceafb48e4b083e292ce0dc0250" - integrity sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ== + version "3.3.1" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.1.tgz#b6662fab6a9b704779e48d083a9fef5a81d2b81e" + integrity sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g== dependencies: arg "^5.0.2" chokidar "^3.5.3" color-name "^1.1.4" - detective "^5.2.1" didyoumean "^1.2.2" dlv "^1.1.3" fast-glob "^3.2.12" glob-parent "^6.0.2" is-glob "^4.0.3" + jiti "^1.17.2" lilconfig "^2.0.6" micromatch "^4.0.5" normalize-path "^3.0.0" object-hash "^3.0.0" picocolors "^1.0.0" - postcss "^8.4.18" + postcss "^8.0.9" postcss-import "^14.1.0" postcss-js "^4.0.0" postcss-load-config "^3.1.4" postcss-nested "6.0.0" - postcss-selector-parser "^6.0.10" + postcss-selector-parser "^6.0.11" postcss-value-parser "^4.2.0" quick-lru "^5.1.1" resolve "^1.22.1" + sucrase "^3.29.0" tapable@^1.0.0: version "1.1.3" @@ -10238,20 +10242,20 @@ terminal-link@^2.0.0: supports-hyperlinks "^2.0.0" terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.2.5: - version "5.3.6" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c" - integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ== + version "5.3.7" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7" + integrity sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw== dependencies: - "@jridgewell/trace-mapping" "^0.3.14" + "@jridgewell/trace-mapping" "^0.3.17" jest-worker "^27.4.5" schema-utils "^3.1.1" - serialize-javascript "^6.0.0" - terser "^5.14.1" + serialize-javascript "^6.0.1" + terser "^5.16.5" -terser@^5.0.0, terser@^5.10.0, terser@^5.14.1: - version "5.15.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.1.tgz#8561af6e0fd6d839669c73b92bdd5777d870ed6c" - integrity sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw== +terser@^5.0.0, terser@^5.10.0, terser@^5.16.5: + version "5.16.9" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.9.tgz#7a28cb178e330c484369886f2afd623d9847495f" + integrity sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg== dependencies: "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" @@ -10272,10 +10276,24 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + throat@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" - integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + version "6.0.2" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" + integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== through@^2.3.8: version "2.3.8" @@ -10343,13 +10361,18 @@ tryer@^1.0.1: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + tsconfig-paths@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" - integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== + version "3.14.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== dependencies: "@types/json5" "^0.0.29" - json5 "^1.0.1" + json5 "^1.0.2" minimist "^1.2.6" strip-bom "^3.0.0" @@ -10358,10 +10381,10 @@ tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== tsutils@^3.21.0: version "3.21.0" @@ -10419,6 +10442,15 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -10468,10 +10500,10 @@ unicode-match-property-ecmascript@^2.0.0: unicode-canonical-property-names-ecmascript "^2.0.0" unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== unicode-property-aliases-ecmascript@^2.0.0: version "2.1.0" @@ -10517,7 +10549,7 @@ upath@^1.2.0: resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -update-browserslist-db@^1.0.9: +update-browserslist-db@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== @@ -10545,6 +10577,26 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +use-callback-ref@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" + integrity sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w== + dependencies: + tslib "^2.0.0" + +use-isomorphic-layout-effect@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" + integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== + +use-sidecar@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" + integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + use-sync-external-store@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" @@ -10662,9 +10714,9 @@ webpack-dev-middleware@^5.3.1: schema-utils "^4.0.0" webpack-dev-server@^4.6.0: - version "4.11.1" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz#ae07f0d71ca0438cf88446f09029b92ce81380b5" - integrity sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw== + version "4.13.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.13.2.tgz#d97445481d78691efe6d9a3b230833d802fc31f9" + integrity sha512-5i6TrGBRxG4vnfDpB6qSQGfnB6skGBXNL5/542w2uRGLimX6qeE5BQMLrzIC3JYV/xlGOv+s+hTleI9AZKUQNw== dependencies: "@types/bonjour" "^3.5.9" "@types/connect-history-api-fallback" "^1.3.5" @@ -10685,6 +10737,7 @@ webpack-dev-server@^4.6.0: html-entities "^2.3.2" http-proxy-middleware "^2.0.3" ipaddr.js "^2.0.1" + launch-editor "^2.6.0" open "^8.0.9" p-retry "^4.5.0" rimraf "^3.0.2" @@ -10694,7 +10747,7 @@ webpack-dev-server@^4.6.0: sockjs "^0.3.24" spdy "^4.0.2" webpack-dev-middleware "^5.3.1" - ws "^8.4.2" + ws "^8.13.0" webpack-manifest-plugin@^4.0.2: version "4.1.1" @@ -10726,9 +10779,9 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.64.4: - version "5.76.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.76.1.tgz#7773de017e988bccb0f13c7d75ec245f377d295c" - integrity sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ== + version "5.78.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.78.0.tgz#836452a12416af2a7beae906b31644cb2562f9e6" + integrity sha512-gT5DP72KInmE/3azEaQrISjTvLYlSM0j1Ezhht/KLVkrqtv10JoP/RXhwmX/frrutOPuSq3o5Vq0ehR/4Vmd1g== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" @@ -10821,7 +10874,7 @@ whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: tr46 "^2.1.0" webidl-conversions "^6.1.0" -which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2: +which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== @@ -10842,17 +10895,17 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -which-typed-array@^1.1.2: - version "1.1.8" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.8.tgz#0cfd53401a6f334d90ed1125754a42ed663eb01f" - integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw== +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== dependencies: available-typed-arrays "^1.0.5" call-bind "^1.0.2" - es-abstract "^1.20.0" for-each "^0.3.3" + gopd "^1.0.1" has-tostringtag "^1.0.0" - is-typed-array "^1.1.9" + is-typed-array "^1.1.10" which@^1.3.1: version "1.3.1" @@ -11080,10 +11133,10 @@ ws@^7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -ws@^8.4.2: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" - integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== +ws@^8.13.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== ws@~6.1.0: version "6.1.4" @@ -11112,16 +11165,16 @@ xmlhttprequest@1.8.0: resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" integrity sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA== -xtend@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" From a89952e32f965ecdd8bff197bd156379866b1c7e Mon Sep 17 00:00:00 2001 From: Excalidraw Bot <77840495+excalibot@users.noreply.github.com> Date: Thu, 18 May 2023 16:23:09 +0200 Subject: [PATCH 074/451] chore: Update translations from Crowdin (#6589) --- src/locales/ar-SA.json | 65 ++++++++-------------- src/locales/bg-BG.json | 65 ++++++++-------------- src/locales/bn-BD.json | 65 ++++++++-------------- src/locales/ca-ES.json | 65 ++++++++-------------- src/locales/cs-CZ.json | 65 ++++++++-------------- src/locales/da-DK.json | 65 ++++++++-------------- src/locales/de-DE.json | 65 ++++++++-------------- src/locales/el-GR.json | 65 ++++++++-------------- src/locales/es-ES.json | 65 ++++++++-------------- src/locales/eu-ES.json | 79 ++++++++++----------------- src/locales/fa-IR.json | 65 ++++++++-------------- src/locales/fi-FI.json | 65 ++++++++-------------- src/locales/fr-FR.json | 65 ++++++++-------------- src/locales/gl-ES.json | 65 ++++++++-------------- src/locales/he-IL.json | 65 ++++++++-------------- src/locales/hi-IN.json | 65 ++++++++-------------- src/locales/hu-HU.json | 65 ++++++++-------------- src/locales/id-ID.json | 65 ++++++++-------------- src/locales/it-IT.json | 73 +++++++++---------------- src/locales/ja-JP.json | 65 ++++++++-------------- src/locales/kaa.json | 65 ++++++++-------------- src/locales/kab-KAB.json | 65 ++++++++-------------- src/locales/kk-KZ.json | 65 ++++++++-------------- src/locales/km-KH.json | 65 ++++++++-------------- src/locales/ko-KR.json | 65 ++++++++-------------- src/locales/ku-TR.json | 65 ++++++++-------------- src/locales/lt-LT.json | 65 ++++++++-------------- src/locales/lv-LV.json | 65 ++++++++-------------- src/locales/mr-IN.json | 65 ++++++++-------------- src/locales/my-MM.json | 65 ++++++++-------------- src/locales/nb-NO.json | 65 ++++++++-------------- src/locales/nl-NL.json | 65 ++++++++-------------- src/locales/nn-NO.json | 65 ++++++++-------------- src/locales/oc-FR.json | 65 ++++++++-------------- src/locales/pa-IN.json | 65 ++++++++-------------- src/locales/percentages.json | 102 +++++++++++++++++------------------ src/locales/pl-PL.json | 65 ++++++++-------------- src/locales/pt-BR.json | 81 ++++++++++------------------ src/locales/pt-PT.json | 65 ++++++++-------------- src/locales/ro-RO.json | 65 ++++++++-------------- src/locales/ru-RU.json | 65 ++++++++-------------- src/locales/si-LK.json | 65 ++++++++-------------- src/locales/sk-SK.json | 65 ++++++++-------------- src/locales/sl-SI.json | 65 ++++++++-------------- src/locales/sv-SE.json | 65 ++++++++-------------- src/locales/ta-IN.json | 65 ++++++++-------------- src/locales/th-TH.json | 65 ++++++++-------------- src/locales/tr-TR.json | 65 ++++++++-------------- src/locales/uk-UA.json | 65 ++++++++-------------- src/locales/vi-VN.json | 65 ++++++++-------------- src/locales/zh-CN.json | 65 ++++++++-------------- src/locales/zh-HK.json | 65 ++++++++-------------- src/locales/zh-TW.json | 65 ++++++++-------------- 53 files changed, 1162 insertions(+), 2358 deletions(-) diff --git a/src/locales/ar-SA.json b/src/locales/ar-SA.json index 9bfec8236..c02cd1899 100644 --- a/src/locales/ar-SA.json +++ b/src/locales/ar-SA.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "أبيض", - "f8f9fa": "رمادي 0", - "f1f3f5": "رمادي 1", - "fff5f5": "أحمر 0", - "fff0f6": "وردي 0", - "f8f0fc": "عنبي 0", - "f3f0ff": "بنفسجي 0", - "edf2ff": "نيلي 0", - "e7f5ff": "أزرق 0", - "e3fafc": "سماوي 0", - "e6fcf5": "تركواز 0", - "ebfbee": "أخضر 0", - "f4fce3": "ليموني 0", - "fff9db": "أصفر 0", - "fff4e6": "برتقالي 0", "transparent": "شفاف", - "ced4da": "رمادي 4", - "868e96": "رمادي 6", - "fa5252": "أحمر 6", - "e64980": "وردي 6", - "be4bdb": "عنبي 6", - "7950f2": "بنفسجي 6", - "4c6ef5": "نيلي 6", - "228be6": "أزرق 6", - "15aabf": "سماوي 6", - "12b886": "تركواز 6", - "40c057": "أخضر 6", - "82c91e": "ليموني 6", - "fab005": "أصفر 6", - "fd7e14": "برتقالي 6", - "000000": "أسود", - "343a40": "رمادي 8", - "495057": "رمادي 7", - "c92a2a": "أحمر 9", - "a61e4d": "وردي 9", - "862e9c": "عنبي 9", - "5f3dc4": "بنفسجي 9", - "364fc7": "نيلي 9", - "1864ab": "أزرق 9", - "0b7285": "سماوي 9", - "087f5b": "تركواز 9", - "2b8a3e": "أخضر 9", - "5c940d": "ليموني 9", - "e67700": "أصفر 9", - "d9480f": "برتقالي 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/bg-BG.json b/src/locales/bg-BG.json index ef9a3759d..724a5dcf1 100644 --- a/src/locales/bg-BG.json +++ b/src/locales/bg-BG.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/bn-BD.json b/src/locales/bn-BD.json index d652c1ebc..f7132f8e7 100644 --- a/src/locales/bn-BD.json +++ b/src/locales/bn-BD.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "সাদা", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "কালো", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/ca-ES.json b/src/locales/ca-ES.json index 02bb253d5..c6cb0051b 100644 --- a/src/locales/ca-ES.json +++ b/src/locales/ca-ES.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Fer servir {{shortcut}} per enganxar com un sol element,\no enganxeu-lo en un editor de text existent" }, "colors": { - "ffffff": "Blanc", - "f8f9fa": "Gris 0", - "f1f3f5": "Gris 1", - "fff5f5": "Vermell 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Malva 0", - "f3f0ff": "Violat 0", - "edf2ff": "Indi 0", - "e7f5ff": "Blau 0", - "e3fafc": "Cian 0", - "e6fcf5": "Xarxet 0", - "ebfbee": "Verd 0", - "f4fce3": "Llima 0", - "fff9db": "Groc 0", - "fff4e6": "Taronja 0", "transparent": "Transparent", - "ced4da": "Gris 4", - "868e96": "Gris 6", - "fa5252": "Vermell 6", - "e64980": "Rosa 6", - "be4bdb": "Malva 6", - "7950f2": "Violat 6", - "4c6ef5": "Indi 6", - "228be6": "Blau 6", - "15aabf": "Cian 6", - "12b886": "Xarxet 6", - "40c057": "Verd 6", - "82c91e": "Llima 6", - "fab005": "Groc 6", - "fd7e14": "Taronja 6", - "000000": "Negre", - "343a40": "Gris 8", - "495057": "Gris 7", - "c92a2a": "Vermell 9", - "a61e4d": "Rosa 9", - "862e9c": "Malva 9", - "5f3dc4": "Violat 9", - "364fc7": "Indi 9", - "1864ab": "Blau 9", - "0b7285": "Cian 9", - "087f5b": "Xarxet 9", - "2b8a3e": "Verd 9", - "5c940d": "Llima 9", - "e67700": "Groc 9", - "d9480f": "Taronja 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Selecciona una eina i comença a dibuixar!", "helpHint": "Dreceres i ajuda" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/cs-CZ.json b/src/locales/cs-CZ.json index 3ab4827b7..1b80b7453 100644 --- a/src/locales/cs-CZ.json +++ b/src/locales/cs-CZ.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "Bílá", - "f8f9fa": "Šedá 0", - "f1f3f5": "Šedá 1", - "fff5f5": "Červená 0", - "fff0f6": "Růžová 0", - "f8f0fc": "Vínová 0", - "f3f0ff": "Fialová 0", - "edf2ff": "Indigová 0", - "e7f5ff": "Modrá 0", - "e3fafc": "Azurová 0", - "e6fcf5": "Modrozelená 0", - "ebfbee": "Zelená 0", - "f4fce3": "Limetková 0", - "fff9db": "Žlutá 0", - "fff4e6": "Oranžová 0", "transparent": "Průhledná", - "ced4da": "Šedá 4", - "868e96": "Šedá 6", - "fa5252": "Červená 6", - "e64980": "Růžová 6", - "be4bdb": "Vínová 6", - "7950f2": "Fialová 6", - "4c6ef5": "Indigová 6", - "228be6": "Modrá 6", - "15aabf": "Azurová 6", - "12b886": "Modrozelená 6", - "40c057": "Zelená 6", - "82c91e": "Limetková 6", - "fab005": "Žlutá 6", - "fd7e14": "Oranžová 6", - "000000": "Černá", - "343a40": "Šedá 8", - "495057": "Šedá 7", - "c92a2a": "Červená 9", - "a61e4d": "Růžová 9", - "862e9c": "Vínová 9", - "5f3dc4": "Fialová 9", - "364fc7": "Indigová 9", - "1864ab": "Modrá 9", - "0b7285": "Azurová 9", - "087f5b": "Modrozelená 9", - "2b8a3e": "Zelená 9", - "5c940d": "Limetková 9", - "e67700": "Žlutá 9", - "d9480f": "Oranzova" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/da-DK.json b/src/locales/da-DK.json index 15801ed4d..c4ed43571 100644 --- a/src/locales/da-DK.json +++ b/src/locales/da-DK.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/de-DE.json b/src/locales/de-DE.json index f28dc123b..8e5518569 100644 --- a/src/locales/de-DE.json +++ b/src/locales/de-DE.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Verwende {{shortcut}} , um als einzelnes Element\neinzufügen oder in einen existierenden Texteditor einzufügen" }, "colors": { - "ffffff": "Weiß", - "f8f9fa": "Grau 0", - "f1f3f5": "Grau 1", - "fff5f5": "Rot 0", - "fff0f6": "Pink 0", - "f8f0fc": "Traube 0", - "f3f0ff": "Violett 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Blau 0", - "e3fafc": "Cyan 0", - "e6fcf5": "Teal 0", - "ebfbee": "Grün 0", - "f4fce3": "Hellgrün 0", - "fff9db": "Gelb 0", - "fff4e6": "Orange 0", "transparent": "Transparent", - "ced4da": "Grau 4", - "868e96": "Grau 6", - "fa5252": "Rot 6", - "e64980": "Pink 6", - "be4bdb": "Traube 6", - "7950f2": "Violett 6", - "4c6ef5": "Indigo 6", - "228be6": "Blau 6", - "15aabf": "Cyan 6", - "12b886": "Teal 6", - "40c057": "Grün 6", - "82c91e": "Hellgrün 6", - "fab005": "Gelb 6", - "fd7e14": "Orange 6", - "000000": "Schwarz", - "343a40": "Grau 8", - "495057": "Grau 7", - "c92a2a": "Rot 9", - "a61e4d": "Pink 9", - "862e9c": "Traube 9", - "5f3dc4": "Violett 9", - "364fc7": "Indigo 9", - "1864ab": "Blau 9", - "0b7285": "Cyan 9", - "087f5b": "Teal 9", - "2b8a3e": "Grün 9", - "5c940d": "Hellgrün 9", - "e67700": "Gelb 9", - "d9480f": "Orange 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Wähle ein Werkzeug & beginne zu zeichnen!", "helpHint": "Kurzbefehle & Hilfe" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/el-GR.json b/src/locales/el-GR.json index ddd6af340..e1008e05c 100644 --- a/src/locales/el-GR.json +++ b/src/locales/el-GR.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Χρησιμοποίησε το {{shortcut}} για να επικολλήσεις ως ένα μόνο στοιχείο,\nή να επικολλήσεις σε έναν υπάρχοντα επεξεργαστή κειμένου" }, "colors": { - "ffffff": "Λευκό", - "f8f9fa": "Γκρι 0", - "f1f3f5": "Γκρι 1", - "fff5f5": "Κόκκινο 0", - "fff0f6": "Ροζ 0", - "f8f0fc": "Σταφυλί 0", - "f3f0ff": "Βιολετί 0", - "edf2ff": "Λουλάκι 0", - "e7f5ff": "Μπλε 0", - "e3fafc": "Κυανό 0", - "e6fcf5": "Τιρκουάζ 0", - "ebfbee": "Πράσινο 0", - "f4fce3": "Πρασινοκίτρινο 0", - "fff9db": "Κίτρινο 0", - "fff4e6": "Πορτοκαλί 0", "transparent": "Διαφανές", - "ced4da": "Γκρι 4", - "868e96": "Γκρι 6", - "fa5252": "Κόκκινο 6", - "e64980": "Ροζ 6", - "be4bdb": "Σταφυλί 6", - "7950f2": "Βιολετί 6", - "4c6ef5": "Λουλάκι 6", - "228be6": "Μπλε 6", - "15aabf": "Κυανό 6", - "12b886": "Τιρκουάζ 6", - "40c057": "Πράσινο 6", - "82c91e": "Πρασινοκίτρινο 6", - "fab005": "Κίτρινο 6", - "fd7e14": "Πορτοκαλί 6", - "000000": "Μαύρο", - "343a40": "Γκρι 8", - "495057": "Γκρι 7", - "c92a2a": "Κόκκινο 9", - "a61e4d": "Ροζ 9", - "862e9c": "Σταφυλί 9", - "5f3dc4": "Βιολετί 9", - "364fc7": "Λουλάκι 9", - "1864ab": "Μπλε 9", - "0b7285": "Κυανό 9", - "087f5b": "Τιρκουάζ 9", - "2b8a3e": "Πράσινο 9", - "5c940d": "Πρασινοκίτρινο 9", - "e67700": "Κίτρινο 9", - "d9480f": "Πορτοκαλί 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Επιλέξτε ένα εργαλείο και ξεκινήστε να σχεδιάζεται!", "helpHint": "Συντομεύσεις και βοήθεια" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/es-ES.json b/src/locales/es-ES.json index 594efb663..bf6a80c3e 100644 --- a/src/locales/es-ES.json +++ b/src/locales/es-ES.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Usa {{shortcut}} para pegar como un solo elemento,\no pegar en un editor de texto existente" }, "colors": { - "ffffff": "Blanco", - "f8f9fa": "Gris 0", - "f1f3f5": "Gris 1", - "fff5f5": "Rojo 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Uva 0", - "f3f0ff": "Violeta 0", - "edf2ff": "Índigo 0", - "e7f5ff": "Azul 0", - "e3fafc": "Cian 0", - "e6fcf5": "Turquesa 0", - "ebfbee": "Verde 0", - "f4fce3": "Lima 0", - "fff9db": "Amarillo 0", - "fff4e6": "Naranja 0", "transparent": "Transparente", - "ced4da": "Gris 4", - "868e96": "Gris 6", - "fa5252": "Rojo 6", - "e64980": "Rosa 6", - "be4bdb": "Uva 6", - "7950f2": "Violeta 6", - "4c6ef5": "Índigo 6", - "228be6": "Azul 6", - "15aabf": "Cian 6", - "12b886": "Turquesa 6", - "40c057": "Verde 6", - "82c91e": "Lima 6", - "fab005": "Amarillo 6", - "fd7e14": "Naranja 6", - "000000": "Negro", - "343a40": "Gris 8", - "495057": "Gris 7", - "c92a2a": "Rojo 9", - "a61e4d": "Rosa 9", - "862e9c": "Uva 9", - "5f3dc4": "Violeta 9", - "364fc7": "Índigo 9", - "1864ab": "Azul 9", - "0b7285": "Cian 9", - "087f5b": "Turquesa 9", - "2b8a3e": "Verde 9", - "5c940d": "Lima 9", - "e67700": "Amarillo 9", - "d9480f": "Naranja 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "¡Elige una herramienta y empieza a dibujar!", "helpHint": "Atajos y ayuda" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/eu-ES.json b/src/locales/eu-ES.json index a3fd66cf0..379fb89bc 100644 --- a/src/locales/eu-ES.json +++ b/src/locales/eu-ES.json @@ -54,7 +54,7 @@ "veryLarge": "Oso handia", "solid": "Solidoa", "hachure": "Itzalduna", - "zigzag": "", + "zigzag": "Sigi-saga", "crossHatch": "Marraduna", "thin": "Mehea", "bold": "Lodia", @@ -208,10 +208,10 @@ "collabSaveFailed": "Ezin izan da backend datu-basean gorde. Arazoak jarraitzen badu, zure fitxategia lokalean gorde beharko zenuke zure lana ez duzula galtzen ziurtatzeko.", "collabSaveFailed_sizeExceeded": "Ezin izan da backend datu-basean gorde, ohiala handiegia dela dirudi. Fitxategia lokalean gorde beharko zenuke zure lana galtzen ez duzula ziurtatzeko.", "brave_measure_text_error": { - "line1": "", - "line2": "", - "line3": "", - "line4": "" + "line1": "Brave arakatzailea erabiltzen ari zarela dirudi Blokeatu hatz-markak erasokorki ezarpena gaituta.", + "line2": "Honek zure marrazkietako Testu-elementuak hautsi ditzake.", + "line3": "Ezarpen hau desgaitzea gomendatzen dugu. urrats hauek jarrai ditzakezu hori nola egin jakiteko.", + "line4": "Ezarpen hau desgaituz gero, testu-elementuen bistaratzea konpontzen ez bada, ireki arazo gure GitHub-en edo idatzi iezaguzu Discord helbidera" } }, "toolBar": { @@ -306,8 +306,8 @@ "doubleClick": "klik bikoitza", "drag": "arrastatu", "editor": "Editorea", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Editatu lerroak/gezi-puntuak", + "editText": "Editatu testua / gehitu etiketa", "github": "Arazorik izan al duzu? Eman horren berri", "howto": "Jarraitu gure gidak", "or": "edo", @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Erabili {{shortcut}} elementu bakar gisa itsasteko,\nedo itsatsi lehendik dagoen testu-editore batean" }, "colors": { - "ffffff": "Zuria", - "f8f9fa": "Grisa 0", - "f1f3f5": "Grisa 1", - "fff5f5": "Gorria 0", - "fff0f6": "Arrosa 0", - "f8f0fc": "Mahats kolorea 0", - "f3f0ff": "Bioleta 0", - "edf2ff": "Indigoa 0", - "e7f5ff": "Urdina 0", - "e3fafc": "Ziana 0", - "e6fcf5": "Berde urdinxka 0", - "ebfbee": "Berdea 0", - "f4fce3": "Lima 0", - "fff9db": "Horia 0", - "fff4e6": "Laranja 0", "transparent": "Gardena", - "ced4da": "Grisa 4", - "868e96": "Grisa 6", - "fa5252": "Gorria 6", - "e64980": "Arrosa 6", - "be4bdb": "Mahats kolorea 6", - "7950f2": "Bioleta 6", - "4c6ef5": "Indigoa 6", - "228be6": "Urdina 6", - "15aabf": "Ziana 6", - "12b886": "Berde urdinxka 6", - "40c057": "Berdea 6", - "82c91e": "Lima 6", - "fab005": "Horia 6", - "fd7e14": "Laranja 6", - "000000": "Beltza", - "343a40": "Grisa 8", - "495057": "Grisa 7", - "c92a2a": "Gorria 9", - "a61e4d": "Arrosa 9", - "862e9c": "Mahats kolorea 9", - "5f3dc4": "Bioleta 9", - "364fc7": "Indigoa 9", - "1864ab": "Urdina 9", - "0b7285": "Ziana 9", - "087f5b": "Berde urdinxka 9", - "2b8a3e": "Berdea 9", - "5c940d": "Lima 9", - "e67700": "Horia 9", - "d9480f": "Laranja 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Aukeratu tresna bat eta hasi marrazten!", "helpHint": "Lasterbideak eta laguntza" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/fa-IR.json b/src/locales/fa-IR.json index cf793845d..4f9ae9858 100644 --- a/src/locales/fa-IR.json +++ b/src/locales/fa-IR.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "از {{shortcut}} برای چسباندن به عنوان یک عنصر استفاده کنید،\nیا در یک ویرایشگر متن موجود جایگذاری کنید" }, "colors": { - "ffffff": "سفید", - "f8f9fa": "خاکستری 0", - "f1f3f5": "خاکستری 1", - "fff5f5": "قرمز 0", - "fff0f6": "صورتی 0", - "f8f0fc": "انگوری 0", - "f3f0ff": "بنفش 0", - "edf2ff": "نیلی 0", - "e7f5ff": "آبی 0", - "e3fafc": "آبی نفتی 0", - "e6fcf5": "آبی فیروزه ای 0", - "ebfbee": "سبز 0", - "f4fce3": "لیمویی 0", - "fff9db": "زرد 0", - "fff4e6": "نارنجی 0", "transparent": "شفاف", - "ced4da": "خاکستری 4", - "868e96": "خاکستری 6", - "fa5252": "قرمز 6", - "e64980": "صورتی 6", - "be4bdb": "انگوری 6", - "7950f2": "بنفش 6", - "4c6ef5": "نیلی 6", - "228be6": "آبی 6", - "15aabf": "آبی نفتی 6", - "12b886": "آبی فیروزه ای 6", - "40c057": "سبز 6", - "82c91e": "لیمویی 6", - "fab005": "زرد 6", - "fd7e14": "نارنجی 6", - "000000": "سیاه", - "343a40": "خاکستری 8", - "495057": "خاکستری 7", - "c92a2a": "قرمز 9", - "a61e4d": "صورتی 9", - "862e9c": "انگوری 9", - "5f3dc4": "بنفش 9", - "364fc7": "نیلی 9", - "1864ab": "آبی 9", - "0b7285": "آبی نفتی 9", - "087f5b": "آبی فیروزه ای 9", - "2b8a3e": "سبز 9", - "5c940d": "لیمویی 9", - "e67700": "زرد 9", - "d9480f": "نارنجی 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "ابزاری را انتخاب کنید و نقاشی را شروع کنید!", "helpHint": "میانبرها و راهنما" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/fi-FI.json b/src/locales/fi-FI.json index 399876265..a7a354dcd 100644 --- a/src/locales/fi-FI.json +++ b/src/locales/fi-FI.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Käytä {{shortcut}} liittääksesi yhtenä elementtinä,\ntai liittääksesi olemassa olevaan tekstieditoriin" }, "colors": { - "ffffff": "Valkoinen", - "f8f9fa": "Harmaa 0", - "f1f3f5": "Harmaa 1", - "fff5f5": "Punainen 0", - "fff0f6": "Pinkki 0", - "f8f0fc": "Rypäle 0", - "f3f0ff": "Violetti 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Sininen 0", - "e3fafc": "Syaani 0", - "e6fcf5": "Sinivihreä 0", - "ebfbee": "Vihreä 0", - "f4fce3": "Limenvihreä 0", - "fff9db": "Keltainen 0", - "fff4e6": "Oranssi 0", "transparent": "Läpinäkyvä", - "ced4da": "Harmaa 4", - "868e96": "Harmaa 6", - "fa5252": "Punainen 6", - "e64980": "Pinkki 6", - "be4bdb": "Rypäle 6", - "7950f2": "Violetti 6", - "4c6ef5": "Indigo 6", - "228be6": "Sininen 6", - "15aabf": "Syaani 6", - "12b886": "Sinivihreä 6", - "40c057": "Vihreä 6", - "82c91e": "Limenvihreä 6", - "fab005": "Keltainen 6", - "fd7e14": "Oranssi 6", - "000000": "Musta", - "343a40": "Harmaa 8", - "495057": "Harmaa 7", - "c92a2a": "Punainen 9", - "a61e4d": "Pinkki 9", - "862e9c": "Rypäle 9", - "5f3dc4": "Violetti 9", - "364fc7": "Indigo 9", - "1864ab": "Sininen 9", - "0b7285": "Syaani 9", - "087f5b": "Sinivihreä 9", - "2b8a3e": "Vihreä 9", - "5c940d": "Limenvihreä 9", - "e67700": "Keltainen 9", - "d9480f": "Oranssi 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Valitse työkalu ja aloita piirtäminen!", "helpHint": "Pikanäppäimet & ohje" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/fr-FR.json b/src/locales/fr-FR.json index b97f2c285..93a761afd 100644 --- a/src/locales/fr-FR.json +++ b/src/locales/fr-FR.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Utiliser {{shortcut}} pour coller comme un seul élément,\nou coller dans un éditeur de texte existant" }, "colors": { - "ffffff": "Blanc", - "f8f9fa": "Gris 0", - "f1f3f5": "Gris 1", - "fff5f5": "Rouge 0", - "fff0f6": "Rose 0", - "f8f0fc": "Mauve 0", - "f3f0ff": "Violet 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Bleu 0", - "e3fafc": "Cyan 0", - "e6fcf5": "Turquoise 0", - "ebfbee": "Vert 0", - "f4fce3": "Citron vert 0", - "fff9db": "Jaune 0", - "fff4e6": "Orange 0", "transparent": "Transparent", - "ced4da": "Gris 4", - "868e96": "Gris 6", - "fa5252": "Rouge 6", - "e64980": "Rose 6", - "be4bdb": "Mauve 6", - "7950f2": "Violet 6", - "4c6ef5": "Indigo 6", - "228be6": "Bleu 6", - "15aabf": "Cyan 6", - "12b886": "Turquoise 6", - "40c057": "Vert 6", - "82c91e": "Citron vert 6", - "fab005": "Jaune 6", - "fd7e14": "Orange 6", - "000000": "Noir", - "343a40": "Gris 8", - "495057": "Gris 7", - "c92a2a": "Rouge 9", - "a61e4d": "Rose 9", - "862e9c": "Mauve 9", - "5f3dc4": "Violet 9", - "364fc7": "Indigo 9", - "1864ab": "Bleu 9", - "0b7285": "Cyan 9", - "087f5b": "Turquoise 9", - "2b8a3e": "Vert 9", - "5c940d": "Citron vert 9", - "e67700": "Jaune 9", - "d9480f": "Orange 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Choisissez un outil et commencez à dessiner !", "helpHint": "Raccourcis et aide" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/gl-ES.json b/src/locales/gl-ES.json index 602ddac17..7938f7aed 100644 --- a/src/locales/gl-ES.json +++ b/src/locales/gl-ES.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Usa {{shortcut}} para pegar como un único elemento\nou pega nun editor de texto existente" }, "colors": { - "ffffff": "Branco", - "f8f9fa": "Gris 0", - "f1f3f5": "Gris 1", - "fff5f5": "Vermello 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Uva 0", - "f3f0ff": "Violeta 0", - "edf2ff": "Índigo 0", - "e7f5ff": "Azul 0", - "e3fafc": "Ciano 0", - "e6fcf5": "Turquesa 0", - "ebfbee": "Verde 0", - "f4fce3": "Lima 0", - "fff9db": "Amarelo 0", - "fff4e6": "Laranxa 0", "transparent": "Transparente", - "ced4da": "Gris 4", - "868e96": "Gris 6", - "fa5252": "Vermello 6", - "e64980": "Rosa 6", - "be4bdb": "Uva 6", - "7950f2": "Violeta 6", - "4c6ef5": "Índigo 6", - "228be6": "Azul 6", - "15aabf": "Ciano 6", - "12b886": "Turquesa 6", - "40c057": "Verde 6", - "82c91e": "Lima 6", - "fab005": "Amarelo 6", - "fd7e14": "Laranxa 6", - "000000": "Negro", - "343a40": "Gris 8", - "495057": "Gris 7", - "c92a2a": "Vermello 9", - "a61e4d": "Rosa 9", - "862e9c": "Uva 9", - "5f3dc4": "Violeta 9", - "364fc7": "Índigo 9", - "1864ab": "Azul 9", - "0b7285": "Ciano 9", - "087f5b": "Turquesa 9", - "2b8a3e": "Verde 9", - "5c940d": "Lima 9", - "e67700": "Amarelo 9", - "d9480f": "Laranxa 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Escolle unha ferramenta & Comeza a debuxar!", "helpHint": "Atallos & axuda" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/he-IL.json b/src/locales/he-IL.json index 567a96825..813131eaf 100644 --- a/src/locales/he-IL.json +++ b/src/locales/he-IL.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "השתמש ב- {{shortcut}} כדי להדביק כפריט יחיד,\nאו הדבק לתוך עורך טקסט קיים" }, "colors": { - "ffffff": "לבן", - "f8f9fa": "אפור 0", - "f1f3f5": "אפור 1", - "fff5f5": "אדום 0", - "fff0f6": "ורוד 0", - "f8f0fc": "ענבים 0", - "f3f0ff": "סגול 0", - "edf2ff": "כחול כהה 0", - "e7f5ff": "כחול 0", - "e3fafc": "טורקיז 0", - "e6fcf5": "ירקרק 0", - "ebfbee": "ירוק 0", - "f4fce3": "ליים 0", - "fff9db": "צהוב", - "fff4e6": "כתום 0", "transparent": "שקוף", - "ced4da": "אפור 4", - "868e96": "אפור 6", - "fa5252": "אדום 6", - "e64980": "ורוד 6", - "be4bdb": "ענבים 6", - "7950f2": "סגול 6", - "4c6ef5": "כחול כהה 6", - "228be6": "כחול 6", - "15aabf": "טורקיז 6", - "12b886": "ירקרק 6", - "40c057": "ירוק 6", - "82c91e": "ליים 6", - "fab005": "צהוב 6", - "fd7e14": "כתום 6", - "000000": "שחור", - "343a40": "אפור 8", - "495057": "אפור 7", - "c92a2a": "אדום 9", - "a61e4d": "ורוד 9", - "862e9c": "ענבים 9", - "5f3dc4": "סגול 9", - "364fc7": "כחול כהה 9", - "1864ab": "כחול 9", - "0b7285": "טורקיז 9", - "087f5b": "ירוק-כחול 9", - "2b8a3e": "ירוק 9", - "5c940d": "ליים 9", - "e67700": "צהוב 9", - "d9480f": "כתום 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "בחר כלי & והתחל לצייר!", "helpHint": "קיצורים & עזרה" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/hi-IN.json b/src/locales/hi-IN.json index 1c1978bbd..0a4f47d92 100644 --- a/src/locales/hi-IN.json +++ b/src/locales/hi-IN.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "एक अवयव के रूप में चिपकाने के लिए {{shortcut}} का उपयोग करें,\nया किसी मौजूदा पाठ संपादक में चिपकायें" }, "colors": { - "ffffff": "सफेद", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "अंगूरी 0", - "f3f0ff": "", - "edf2ff": "नील 0", - "e7f5ff": "नीला 0", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "आसमानी", - "087f5b": "", - "2b8a3e": "हरा", - "5c940d": "", - "e67700": "पीला", - "d9480f": "नारंगी" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "एक औजार चुने और चित्रकारी प्रारंभ करे!", "helpHint": "शॉर्ट्कट और सहाय्य" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/hu-HU.json b/src/locales/hu-HU.json index a54dde9f6..3a4cf1d5a 100644 --- a/src/locales/hu-HU.json +++ b/src/locales/hu-HU.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "Fehér", - "f8f9fa": "Szürke 0", - "f1f3f5": "Szürke 1", - "fff5f5": "Piros 0", - "fff0f6": "Pink 0", - "f8f0fc": "Szőlő 0", - "f3f0ff": "Ibolya 0", - "edf2ff": "Indigó 0", - "e7f5ff": "Kék 0", - "e3fafc": "Cián 0", - "e6fcf5": "Kékes-zöld 0", - "ebfbee": "Zöld 0", - "f4fce3": "Lime 0", - "fff9db": "Sárga 0", - "fff4e6": "Narancs 0", "transparent": "Átlátszó", - "ced4da": "Szürke 4", - "868e96": "Szürke 6", - "fa5252": "Piros 6", - "e64980": "Pink 6", - "be4bdb": "Szőlő 6", - "7950f2": "Ibolya 6", - "4c6ef5": "Indigó 6", - "228be6": "Kék 6", - "15aabf": "Cián 6", - "12b886": "Kékes-zöld 6", - "40c057": "Zöld 6", - "82c91e": "Lime 6", - "fab005": "Sárga 6", - "fd7e14": "Narancs 6", - "000000": "Fekete", - "343a40": "Szürke 8", - "495057": "Szürke 7", - "c92a2a": "Piros 9", - "a61e4d": "Pink 9", - "862e9c": "Szőlő 9", - "5f3dc4": "Ibolya 9", - "364fc7": "Indigó 9", - "1864ab": "Kék 9", - "0b7285": "Cián 9", - "087f5b": "Kékes-zöld 9", - "2b8a3e": "Zöld 9", - "5c940d": "Lime 9", - "e67700": "Sárga 9", - "d9480f": "Narancs 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/id-ID.json b/src/locales/id-ID.json index bb83459dc..37ecf6a18 100644 --- a/src/locales/id-ID.json +++ b/src/locales/id-ID.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Gunakan {{shortcut}} untuk menempelkan sebagai satu elemen,\natau tempelkan ke teks editor yang ada" }, "colors": { - "ffffff": "Putih", - "f8f9fa": "Abu-abu 0", - "f1f3f5": "Abu-abu 1", - "fff5f5": "Merah 0", - "fff0f6": "Merah muda 0", - "f8f0fc": "Ungu 0", - "f3f0ff": "Violet 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Biru 0", - "e3fafc": "Cyan 0", - "e6fcf5": "Teal 0", - "ebfbee": "Hijau 0", - "f4fce3": "Lime 0", - "fff9db": "Kuning 0", - "fff4e6": "Jingga 0", "transparent": "Transparan", - "ced4da": "Abu-abu 4", - "868e96": "Abu-abu 6", - "fa5252": "Merah 6", - "e64980": "Merah muda 6", - "be4bdb": "Ungu 6", - "7950f2": "Violet 6", - "4c6ef5": "Indigo 6", - "228be6": "Biru 6", - "15aabf": "Cyan 6", - "12b886": "Teal 6", - "40c057": "Hijau 6", - "82c91e": "Lime 6", - "fab005": "Kuning 6", - "fd7e14": "Jingga 6", - "000000": "Hitam", - "343a40": "Abu-abu 8", - "495057": "Abu-abu 7", - "c92a2a": "Merah 9", - "a61e4d": "Merah muda 9", - "862e9c": "Ungu 9", - "5f3dc4": "Violet 9", - "364fc7": "Indigo 9", - "1864ab": "Biru 9", - "0b7285": "Cyan 9", - "087f5b": "Teal 9", - "2b8a3e": "Hijau 9", - "5c940d": "Lime 9", - "e67700": "Kuning 9", - "d9480f": "Jingga 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Pilih alat & mulai menggambar!", "helpHint": "Pintasan & bantuan" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/it-IT.json b/src/locales/it-IT.json index 12d215623..d8e8afd5a 100644 --- a/src/locales/it-IT.json +++ b/src/locales/it-IT.json @@ -208,10 +208,10 @@ "collabSaveFailed": "Impossibile salvare nel database di backend. Se i problemi persistono, dovresti salvare il tuo file localmente per assicurarti di non perdere il tuo lavoro.", "collabSaveFailed_sizeExceeded": "Impossibile salvare nel database di backend, la tela sembra essere troppo grande. Dovresti salvare il file localmente per assicurarti di non perdere il tuo lavoro.", "brave_measure_text_error": { - "line1": "", - "line2": "", - "line3": "", - "line4": "" + "line1": "Sembra che tu stia utilizzando il browser Brave con l'impostazione Blocco aggressivo delle impronte digitali abilitata.", + "line2": "Ciò potrebbe causare la rottura degli Elementi di testo nei tuoi disegni.", + "line3": "Consigliamo vivamente di disabilitare questa impostazione. Puoi seguire questi passaggi su come farlo.", + "line4": "Se la disattivazione di questa impostazione non risolve la visualizzazione degli elementi di testo, apri un problema sul nostro GitHub o scrivici su Discord" } }, "toolBar": { @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Usa {{shortcut}} per incollare come un singolo elemento,\no incollare in un editor di testo esistente" }, "colors": { - "ffffff": "Bianco", - "f8f9fa": "Grigio 0", - "f1f3f5": "Grigio 1", - "fff5f5": "Rosso 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Uva 0", - "f3f0ff": "Viola 0", - "edf2ff": "Indaco 0", - "e7f5ff": "Blu 0", - "e3fafc": "Ciano 0", - "e6fcf5": "Verde acqua 0", - "ebfbee": "Verde 0", - "f4fce3": "Lime 0", - "fff9db": "Giallo 0", - "fff4e6": "Arancio 0", "transparent": "Trasparente", - "ced4da": "Grigio 4", - "868e96": "Grigio 6", - "fa5252": "Rosso 6", - "e64980": "Rosa 6", - "be4bdb": "Uva 6", - "7950f2": "Viola 6", - "4c6ef5": "Indaco 6", - "228be6": "Blu 6", - "15aabf": "Ciano 6", - "12b886": "Verde acqua 6", - "40c057": "Verde 6", - "82c91e": "Lime 6", - "fab005": "Giallo 6", - "fd7e14": "Arancio 6", - "000000": "Nero", - "343a40": "Grigio 8", - "495057": "Grigio 7", - "c92a2a": "Rosso 9", - "a61e4d": "Rosa 9", - "862e9c": "Uva 9", - "5f3dc4": "Viola 9", - "364fc7": "Indaco 9", - "1864ab": "Blu 9", - "0b7285": "Ciano 9", - "087f5b": "Verde acqua 9", - "2b8a3e": "Verde 9", - "5c940d": "Lime 9", - "e67700": "Giallo 9", - "d9480f": "Arancio 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Scegli uno strumento & Inizia a disegnare!", "helpHint": "Scorciatoie & aiuto" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/ja-JP.json b/src/locales/ja-JP.json index fd4f2c2c7..f11b4c5b3 100644 --- a/src/locales/ja-JP.json +++ b/src/locales/ja-JP.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "{{shortcut}} を使用して単一の要素として貼り付けるか、\n既存のテキストエディタに貼り付け" }, "colors": { - "ffffff": "ホワイト", - "f8f9fa": "グレー 0", - "f1f3f5": "グレー 1", - "fff5f5": "レッド 0", - "fff0f6": "ピンク 0", - "f8f0fc": "グレープ 0", - "f3f0ff": "バイオレット 0", - "edf2ff": "インディゴ 0", - "e7f5ff": "ブルー 0", - "e3fafc": "シアン 0", - "e6fcf5": "ティール 0", - "ebfbee": "グリーン 0", - "f4fce3": "ライム 0", - "fff9db": "イエロー 0", - "fff4e6": "オレンジ 0", "transparent": "透明", - "ced4da": "グレー 4", - "868e96": "グレー 6", - "fa5252": "レッド 6", - "e64980": "ピンク 6", - "be4bdb": "グレープ 6", - "7950f2": "バイオレット 6", - "4c6ef5": "インディゴ 6", - "228be6": "ブルー 6", - "15aabf": "シアン 6", - "12b886": "ティール 6", - "40c057": "グリーン 6", - "82c91e": "ライム 6", - "fab005": "イエロー 6", - "fd7e14": "オレンジ 6", - "000000": "ブラック", - "343a40": "グレー 8", - "495057": "グレー 7", - "c92a2a": "レッド 9", - "a61e4d": "ピンク 9", - "862e9c": "グレープ 9", - "5f3dc4": "バイオレット 9", - "364fc7": "インディゴ 9", - "1864ab": "ブルー 9", - "0b7285": "シアン 9", - "087f5b": "ティール 9", - "2b8a3e": "グリーン 9", - "5c940d": "ライム 9", - "e67700": "イエロー 9", - "d9480f": "オレンジ 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "ツールを選んで描き始めよう!", "helpHint": "ショートカットとヘルプ" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/kaa.json b/src/locales/kaa.json index 6a2c194cf..cf1bce08d 100644 --- a/src/locales/kaa.json +++ b/src/locales/kaa.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "Aq", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "Qızıl 0", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "Kók", - "e3fafc": "", - "e6fcf5": "Piruza 0", - "ebfbee": "", - "f4fce3": "", - "fff9db": "Sarı 0", - "fff4e6": "Qızǵılt sarı 0", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "Qızıl 6", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "Kók 6", - "15aabf": "", - "12b886": "Piruza 6", - "40c057": "Jasıl 6", - "82c91e": "", - "fab005": "Sarı 6", - "fd7e14": "", - "000000": "Qara", - "343a40": "", - "495057": "", - "c92a2a": "Qızıl 9", - "a61e4d": "Qızǵılt 9", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "Kók 9", - "0b7285": "", - "087f5b": "", - "2b8a3e": "Jasıl 9", - "5c940d": "", - "e67700": "Sarı 9", - "d9480f": "Qızǵılt sarı 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/kab-KAB.json b/src/locales/kab-KAB.json index 56e82d102..67db65014 100644 --- a/src/locales/kab-KAB.json +++ b/src/locales/kab-KAB.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "Amellal", - "f8f9fa": "Aɣiɣdi 0", - "f1f3f5": "Aɣiɣdi 1", - "fff5f5": "Azeggaɣ", - "fff0f6": "Axuxi 0", - "f8f0fc": "Tiẓurin 0", - "f3f0ff": "Amidadi 0", - "edf2ff": "", - "e7f5ff": "Anili 0", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "Azegzaw 0", - "f4fce3": "Llim 0", - "fff9db": "Awraɣ 0", - "fff4e6": "Aččinawi 0", "transparent": "Afrawan", - "ced4da": "Aɣiɣdi 4", - "868e96": "Aɣiɣdi 6", - "fa5252": "Azeggaɣ 6", - "e64980": "Axuxi 6", - "be4bdb": "", - "7950f2": "Amidadi 6", - "4c6ef5": "", - "228be6": "Anili 6", - "15aabf": "", - "12b886": "", - "40c057": "Azegzaw 0", - "82c91e": "Llim 6", - "fab005": "Awraɣ 6", - "fd7e14": "Aččinawi 6", - "000000": "Aberkan", - "343a40": "Aɣiɣdi 8", - "495057": "Aɣiɣdi 7", - "c92a2a": "Azeggaɣ 9", - "a61e4d": "Axuxi 9", - "862e9c": "Tiẓurin 9", - "5f3dc4": "Amidadi 9", - "364fc7": "", - "1864ab": "Anili 9", - "0b7285": "", - "087f5b": "", - "2b8a3e": "Azegzaw 9", - "5c940d": "Llim 9", - "e67700": "Awraɣ 9", - "d9480f": "Aččinawi 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Fren afecku tebduḍ asuneɣ!", "helpHint": "Inegzumen akked tallelt" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/kk-KZ.json b/src/locales/kk-KZ.json index 3718c7767..89d7c500d 100644 --- a/src/locales/kk-KZ.json +++ b/src/locales/kk-KZ.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/km-KH.json b/src/locales/km-KH.json index c0558015b..a51c437a2 100644 --- a/src/locales/km-KH.json +++ b/src/locales/km-KH.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "កាប់ស្តាំង ០", - "ebfbee": "បៃតង ០", - "f4fce3": "បៃតងខ្ចី ០", - "fff9db": "លឿង ០", - "fff4e6": "ទឹកក្រូច ០", "transparent": "ថ្លាមើលធ្លុះ", - "ced4da": "ប្រផេះ ៤", - "868e96": "ប្រផេះ ៦", - "fa5252": "ក្រហម ៦", - "e64980": "ផ្កាឈូក ៦", - "be4bdb": "ស្វាយចាស់ ៦", - "7950f2": "ស្វាយ​ ៦", - "4c6ef5": "ខៀវចាស់ ៦", - "228be6": "ខៀវ ៦", - "15aabf": "ខៀវខ្ចី ៦", - "12b886": "កាប់ស្តាំង ៦", - "40c057": "បៃតង ៦", - "82c91e": "បៃតងខ្ចី ៦", - "fab005": "លឿង ៦", - "fd7e14": "ទឹកក្រូច ៦", - "000000": "ខ្មៅ", - "343a40": "ប្រផេះ ៨", - "495057": "ប្រផេះ ៧", - "c92a2a": "ក្រហម​ ៩", - "a61e4d": "ផ្កាឈូក ៩", - "862e9c": "ស្វាយចាស់ ៩", - "5f3dc4": "ស្វាយ ៩", - "364fc7": "ខៀវចាស់ ៩", - "1864ab": "ខៀវ ៩", - "0b7285": "ខៀវខ្ចី ៩", - "087f5b": "កាប់ស្តាំង ៩", - "2b8a3e": "បៃតង ៩", - "5c940d": "បៃតងខ្ចី ៩", - "e67700": "លឿង ៩", - "d9480f": "ទឹកក្រូច ៩" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "ជ្រើសរើសឧបករណ៍មួយ និង ចាប់ផ្តើមគូរ!", "helpHint": "ផ្លូវកាត់ &​ ជំនួយ" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/ko-KR.json b/src/locales/ko-KR.json index 20bdd4306..3ec5233d7 100644 --- a/src/locales/ko-KR.json +++ b/src/locales/ko-KR.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "단일 요소로 붙여넣거나, 기존 텍스트 에디터에 붙여넣으려면 {{shortcut}} 을 사용하세요." }, "colors": { - "ffffff": "화이트", - "f8f9fa": "회색 0", - "f1f3f5": "회색 1", - "fff5f5": "빨강색 0", - "fff0f6": "핑크색 0", - "f8f0fc": "그레이프 0", - "f3f0ff": "바이올렛 0", - "edf2ff": "남색 0", - "e7f5ff": "파란색 0", - "e3fafc": "청록색 0", - "e6fcf5": "틸 0", - "ebfbee": "녹색 0", - "f4fce3": "라임 0", - "fff9db": "노란색 0", - "fff4e6": "주황색 0", "transparent": "투명", - "ced4da": "회색 4", - "868e96": "회색 6", - "fa5252": "빨강색 6", - "e64980": "핑크색 6", - "be4bdb": "그레이프 6", - "7950f2": "바이올렛 6", - "4c6ef5": "남색 6", - "228be6": "파란색 6", - "15aabf": "청록색 6", - "12b886": "틸 6", - "40c057": "녹색 6", - "82c91e": "라임 6", - "fab005": "노란색 6", - "fd7e14": "주황색 6", - "000000": "검정색", - "343a40": "회색 8", - "495057": "회색 7", - "c92a2a": "빨강색 9", - "a61e4d": "핑크색 9", - "862e9c": "그레이프 9", - "5f3dc4": "바이올렛 9", - "364fc7": "남색 9", - "1864ab": "파란색 9", - "0b7285": "청록색 9", - "087f5b": "틸 9", - "2b8a3e": "녹색 9", - "5c940d": "라임 9", - "e67700": "노란색 9", - "d9480f": "주황색 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "도구를 선택하고, 그리세요!", "helpHint": "단축키 & 도움말" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/ku-TR.json b/src/locales/ku-TR.json index 1e2afe444..90f4ceec6 100644 --- a/src/locales/ku-TR.json +++ b/src/locales/ku-TR.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "بۆ دانانەوە وەکو یەک توخم یان دانانەوە بۆ نێو دەسکاریکەرێکی دەق کە بوونی هەیە {{shortcut}} بەکاربهێنە" }, "colors": { - "ffffff": "سپی", - "f8f9fa": "خۆڵەمێشی 0", - "f1f3f5": "خۆڵەمێشی 1", - "fff5f5": "سور 0", - "fff0f6": "پەمەی 0", - "f8f0fc": "مێوژی 0", - "f3f0ff": "مۆر 0", - "edf2ff": "نیلی 0", - "e7f5ff": "شین 0", - "e3fafc": "شینی ئاسمانی 0", - "e6fcf5": "سەوزباوی 0", - "ebfbee": "سه‌وز 0", - "f4fce3": "نارنجی 0", - "fff9db": "زەرد 0", - "fff4e6": "پرتەقاڵی 0", "transparent": "ڕوون", - "ced4da": "خۆڵەمێشی 4", - "868e96": "خۆڵەمێشی 6", - "fa5252": "سور 6", - "e64980": "پەمەی 6", - "be4bdb": "مێوژی 6", - "7950f2": "مۆر 6", - "4c6ef5": "نیلی 6", - "228be6": "شین 6", - "15aabf": "شینی ئاسمانی 6", - "12b886": "سەوزباوی 6", - "40c057": "سه‌وز 6", - "82c91e": "نارنجی 6", - "fab005": "زەرد 6", - "fd7e14": "پرتەقاڵی 6", - "000000": "ڕەش", - "343a40": "خۆڵەمێشی 8", - "495057": "خۆڵەمێشی 7", - "c92a2a": "سور 9", - "a61e4d": "پەمەی 9", - "862e9c": "مێوژی 9", - "5f3dc4": "مۆر 9", - "364fc7": "نیلی 9", - "1864ab": "شین 9", - "0b7285": "شینی ئاسمانی 9", - "087f5b": "سەوزباوی 9", - "2b8a3e": "سه‌وز 9", - "5c940d": "نارنجی 9", - "e67700": "زەرد 9", - "d9480f": "پرتەقاڵی 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "ئامرازێک هەڵبگرە و دەستبکە بە کێشان!", "helpHint": "قەدبڕەکان و یارمەتی" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/lt-LT.json b/src/locales/lt-LT.json index 20ce45a5e..7fb6e9ffe 100644 --- a/src/locales/lt-LT.json +++ b/src/locales/lt-LT.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "Balta", - "f8f9fa": "Pilka 0", - "f1f3f5": "Pilka 1", - "fff5f5": "Raudona 0", - "fff0f6": "Rožinė 0", - "f8f0fc": "", - "f3f0ff": "Violetinė 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Mėlyna 0", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "Žalia 0", - "f4fce3": "", - "fff9db": "Geltona 0", - "fff4e6": "Oranžinė 0", "transparent": "Permatoma", - "ced4da": "Pilka 4", - "868e96": "Pilka 6", - "fa5252": "Raudona 6", - "e64980": "Rožinė 6", - "be4bdb": "", - "7950f2": "Violetinė 6", - "4c6ef5": "Indigo 6", - "228be6": "Mėlyna 6", - "15aabf": "", - "12b886": "", - "40c057": "Žalia 6", - "82c91e": "", - "fab005": "Geltona 6", - "fd7e14": "Oranžinė 6", - "000000": "Juoda", - "343a40": "Pilna 8", - "495057": "Pilka 7", - "c92a2a": "Raudona 9", - "a61e4d": "Rožinė 9", - "862e9c": "", - "5f3dc4": "Violetinė 9", - "364fc7": "Indigo 9", - "1864ab": "Mėlyna 9", - "0b7285": "", - "087f5b": "", - "2b8a3e": "Žalia 9", - "5c940d": "", - "e67700": "Geltona 9", - "d9480f": "Oranžinė 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/lv-LV.json b/src/locales/lv-LV.json index c8c90d426..2a5b84055 100644 --- a/src/locales/lv-LV.json +++ b/src/locales/lv-LV.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Izmantojiet {{shortcut}}, lai ielīmētu kā jaunu elementu, vai ielīmētu esošā teksta lauciņā" }, "colors": { - "ffffff": "Balts", - "f8f9fa": "Pelēks 0", - "f1f3f5": "Pelēks 1", - "fff5f5": "Sarkans 0", - "fff0f6": "Rozā 0", - "f8f0fc": "Vīnogu 0", - "f3f0ff": "Violets 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Zils 0", - "e3fafc": "Ciāns 0", - "e6fcf5": "Zilganzaļš 0", - "ebfbee": "Zaļš 0", - "f4fce3": "Laims 0", - "fff9db": "Dzeltens 0", - "fff4e6": "Oranžs 0", "transparent": "Caurspīdīgs", - "ced4da": "Pelēks 4", - "868e96": "Pelēks 6", - "fa5252": "Sarkans 6", - "e64980": "Rozā 6", - "be4bdb": "Vīnogu 6", - "7950f2": "Violets 6", - "4c6ef5": "Indigo 6", - "228be6": "Zils 6", - "15aabf": "Ciāns 6", - "12b886": "Zilganzaļš 6", - "40c057": "Zaļš 6", - "82c91e": "Laims 6", - "fab005": "Dzeltens 6", - "fd7e14": "Oranžs 6", - "000000": "Melns", - "343a40": "Pelēks 8", - "495057": "Pelēks 7", - "c92a2a": "Sarkans 9", - "a61e4d": "Rozā 9", - "862e9c": "Vīnogu 9", - "5f3dc4": "Violets 9", - "364fc7": "Indigo 9", - "1864ab": "Zils 9", - "0b7285": "Ciāns 9", - "087f5b": "Zilganzaļš 9", - "2b8a3e": "Zaļš 9", - "5c940d": "Laims 9", - "e67700": "Dzeltens 9", - "d9480f": "Oranžs 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Izvēlies rīku un sāc zīmēt!", "helpHint": "Īsceļi un palīdzība" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/mr-IN.json b/src/locales/mr-IN.json index 85e346d08..275e1bca9 100644 --- a/src/locales/mr-IN.json +++ b/src/locales/mr-IN.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "एक घटक म्हणून चिपकावण्या साठी {{shortcut}} वापरा,\nकिंवा विद्यमान मजकूर संपादकात चिपकवा" }, "colors": { - "ffffff": "पांढरा", - "f8f9fa": "करडा 0", - "f1f3f5": "करडा 1", - "fff5f5": "लाल 0", - "fff0f6": "गुलाबी 0", - "f8f0fc": "अंगूरी 0", - "f3f0ff": "जांभळा 0", - "edf2ff": "बैंगनी 0", - "e7f5ff": "नीळा 0", - "e3fafc": "आसमानी 0", - "e6fcf5": "पाचू 0", - "ebfbee": "हिरवा 0", - "f4fce3": "लिंबु 0", - "fff9db": "पिवळा 0", - "fff4e6": "नारंगी 0", "transparent": "पारदर्शक", - "ced4da": "करडा 4", - "868e96": "करडा 6", - "fa5252": "लाल 6", - "e64980": "गुलाबी 6", - "be4bdb": "अंगूरी 6", - "7950f2": "जांभळा 6", - "4c6ef5": "बैंगनी 6", - "228be6": "नीळा 6", - "15aabf": "आसमानी 6", - "12b886": "पाचू 6", - "40c057": "हिरवा 6", - "82c91e": "लिंबु 6", - "fab005": "पिवळा 6", - "fd7e14": "नारंगी 6", - "000000": "काळा", - "343a40": "करडा 8", - "495057": "करडा 7", - "c92a2a": "लाल 9", - "a61e4d": "गुलाबी 9", - "862e9c": "अंगूरी 9", - "5f3dc4": "जामुनी 9", - "364fc7": "बैंगनी 9", - "1864ab": "नीला 9", - "0b7285": "आसमानी 9", - "087f5b": "पाचू 9", - "2b8a3e": "हरा 9", - "5c940d": "नीबू 9", - "e67700": "पीला 9", - "d9480f": "नारंगी 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "एक साधन निवडा आणि चित्रीकरण सुरु करा!", "helpHint": "शॉर्टकट आणि सहाय्य" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/my-MM.json b/src/locales/my-MM.json index 50f8bb560..ffca0c201 100644 --- a/src/locales/my-MM.json +++ b/src/locales/my-MM.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/nb-NO.json b/src/locales/nb-NO.json index 66b197317..c624ac8e5 100644 --- a/src/locales/nb-NO.json +++ b/src/locales/nb-NO.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Bruk {{shortcut}} for å lime inn som ett enkelt element,\neller lim inn i en eksisterende tekstbehandler" }, "colors": { - "ffffff": "Hvit", - "f8f9fa": "Grå 0", - "f1f3f5": "Grå 1", - "fff5f5": "Rød 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Drue 0", - "f3f0ff": "Fiolett 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Blå 0", - "e3fafc": "Turkis 0", - "e6fcf5": "Blågrønn 0", - "ebfbee": "Grønn 0", - "f4fce3": "Limegrønn 0", - "fff9db": "Gul 0", - "fff4e6": "Oransje 0", "transparent": "Gjennomsiktig", - "ced4da": "Grå 4", - "868e96": "Grå 6", - "fa5252": "Rød 6", - "e64980": "Rosa 6", - "be4bdb": "Drue 6", - "7950f2": "Fiolett 6", - "4c6ef5": "Indigo 6", - "228be6": "Blå 6", - "15aabf": "Turkis 6", - "12b886": "Blågrønn 6", - "40c057": "Grønn 6", - "82c91e": "Limegrønn 6", - "fab005": "Gul 6", - "fd7e14": "Oransje 6", - "000000": "Sort", - "343a40": "Grå 8", - "495057": "Grå 7", - "c92a2a": "Rød 9", - "a61e4d": "Rosa 9", - "862e9c": "Drue 9", - "5f3dc4": "Fiolett 9", - "364fc7": "Indigo 9", - "1864ab": "Blå 9", - "0b7285": "Turkis 9", - "087f5b": "Blågrønn 9", - "2b8a3e": "Grønn 9", - "5c940d": "Limegrønn 9", - "e67700": "Gul 9", - "d9480f": "Oransje 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Velg et verktøy og start å tegne!", "helpHint": "Snarveier & hjelp" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/nl-NL.json b/src/locales/nl-NL.json index e94b89f0e..af27dd94a 100644 --- a/src/locales/nl-NL.json +++ b/src/locales/nl-NL.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Gebruik {{shortcut}} om te plakken als een enkel element,\nof plak in een bestaande teksteditor" }, "colors": { - "ffffff": "Wit", - "f8f9fa": "Grijs 0", - "f1f3f5": "Grijs 1", - "fff5f5": "Rood 0", - "fff0f6": "Roze 0", - "f8f0fc": "Druiven 0", - "f3f0ff": "Violet 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Blauw 0", - "e3fafc": "Cyaan 0", - "e6fcf5": "Groenblauw 0", - "ebfbee": "Groen 0", - "f4fce3": "Limoen 0", - "fff9db": "Geel 0", - "fff4e6": "Oranje 0", "transparent": "Transparant", - "ced4da": "Grijs 4", - "868e96": "Grijs 6", - "fa5252": "Rood 6", - "e64980": "Roze 6", - "be4bdb": "Druiven 6", - "7950f2": "Violet", - "4c6ef5": "Indigo 6", - "228be6": "Blauw 6", - "15aabf": "Cyaan 6", - "12b886": "Groenblauw 6", - "40c057": "Groen 6", - "82c91e": "Limoen 6", - "fab005": "Geel 6", - "fd7e14": "Oranje 6", - "000000": "Zwart", - "343a40": "Grijs 8", - "495057": "Grijs 7", - "c92a2a": "Rood 9", - "a61e4d": "Roze 9", - "862e9c": "Druiven 9", - "5f3dc4": "Violet 9", - "364fc7": "Indigo 9", - "1864ab": "Blauw 9", - "0b7285": "Cyaan 9", - "087f5b": "Groenblauw 9", - "2b8a3e": "Groen 9", - "5c940d": "Limoen 9", - "e67700": "Geel 9", - "d9480f": "Oranje 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Kies een tool & begin met tekenen!", "helpHint": "Snelkoppelingen en hulp" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/nn-NO.json b/src/locales/nn-NO.json index 755101171..eb2ed1bd7 100644 --- a/src/locales/nn-NO.json +++ b/src/locales/nn-NO.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "Kvit", - "f8f9fa": "Grå 0", - "f1f3f5": "Grå 1", - "fff5f5": "Raud 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Drue 0", - "f3f0ff": "Fiolett 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Blå 0", - "e3fafc": "Turkis 0", - "e6fcf5": "Blågrøn 0", - "ebfbee": "Grøn 0", - "f4fce3": "Limegrøn 0", - "fff9db": "Gul 0", - "fff4e6": "Oransje 0", "transparent": "Gjennomsiktig", - "ced4da": "Grå 4", - "868e96": "Grå 6", - "fa5252": "Raud 6", - "e64980": "Rosa 6", - "be4bdb": "Drue 6", - "7950f2": "Fiolett 6", - "4c6ef5": "Indigo 6", - "228be6": "Blå 6", - "15aabf": "Turkis 6", - "12b886": "Blågrøn 6", - "40c057": "Grøn 6", - "82c91e": "Limegrøn 6", - "fab005": "Gul 6", - "fd7e14": "Oransje 6", - "000000": "Svart", - "343a40": "Grå 8", - "495057": "Grå 7", - "c92a2a": "Raud 9", - "a61e4d": "Rosa 9", - "862e9c": "Drue 9", - "5f3dc4": "Fiolett 9", - "364fc7": "Indigo 9", - "1864ab": "Blå 9", - "0b7285": "Turkis 9", - "087f5b": "Blågrøn 9", - "2b8a3e": "Grøn 9", - "5c940d": "Limegrøn 9", - "e67700": "Gul 9", - "d9480f": "Oransj 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/oc-FR.json b/src/locales/oc-FR.json index a15c33b93..5628692f8 100644 --- a/src/locales/oc-FR.json +++ b/src/locales/oc-FR.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "Blanc", - "f8f9fa": "Gris 0", - "f1f3f5": "Gris 0", - "fff5f5": "Roge 0", - "fff0f6": "Ròse 0", - "f8f0fc": "Bordèu 0", - "f3f0ff": "Violet 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Blau 0", - "e3fafc": "Cian 0", - "e6fcf5": "Esmerauda 0", - "ebfbee": "Verd 0", - "f4fce3": "Verd citron 0", - "fff9db": "Jaune 0", - "fff4e6": "Irange 0", "transparent": "Transparéncia", - "ced4da": "Gris 4", - "868e96": "Gris 6", - "fa5252": "Roge 6", - "e64980": "Ròse 6", - "be4bdb": "Bordèu 6", - "7950f2": "Violet 6", - "4c6ef5": "Indigo 6", - "228be6": "Blau 6", - "15aabf": "Cian 6", - "12b886": "Esmerauda 6", - "40c057": "Verd 6", - "82c91e": "Verd citron 6", - "fab005": "Jaune 6", - "fd7e14": "Irange 6", - "000000": "Negre", - "343a40": "Gris 8", - "495057": "Gris 7", - "c92a2a": "Roge 9", - "a61e4d": "Ròse 9", - "862e9c": "Bordèu 9", - "5f3dc4": "Violet 9", - "364fc7": "Indigo 9", - "1864ab": "Blau 9", - "0b7285": "Cian 9", - "087f5b": "Esmerauda 9", - "2b8a3e": "Verd 9", - "5c940d": "Verd citron 9", - "e67700": "Jaune 9", - "d9480f": "Irange 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Prenètz un esplech e començatz de dessenhar !", "helpHint": "Acorchis e ajuda" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/pa-IN.json b/src/locales/pa-IN.json index 06ae1c178..b270d3e7f 100644 --- a/src/locales/pa-IN.json +++ b/src/locales/pa-IN.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "ਚਿੱਟਾ", - "f8f9fa": "ਸੁਰਮਈ 0", - "f1f3f5": "ਸੁਰਮਈ 1", - "fff5f5": "ਲਾਲ 0", - "fff0f6": "ਗੁਲਾਬੀ 0", - "f8f0fc": "ਅੰਗੂਰੀ 0", - "f3f0ff": "ਜਾਮਣੀ 0", - "edf2ff": "ਗੂੜ੍ਹਾ ਨੀਲਾ 0", - "e7f5ff": "ਨੀਲਾ 0", - "e3fafc": "ਫਿਰੋਜੀ 0", - "e6fcf5": "ਟੀਲ 0", - "ebfbee": "ਹਰਾ 0", - "f4fce3": "ਲਾਇਮ 0", - "fff9db": "ਪੀਲਾ 0", - "fff4e6": "ਸੰਤਰੀ 0", "transparent": "ਪਾਰਦਰਸ਼ੀ", - "ced4da": "ਸੁਰਮਈ 4", - "868e96": "ਸੁਰਮਈ 6", - "fa5252": "ਲਾਲ 6", - "e64980": "ਗੁਲਾਬੀ 6", - "be4bdb": "ਅੰਗੂਰੀ 6", - "7950f2": "ਜਾਮਣੀ 6", - "4c6ef5": "ਗੂੜ੍ਹਾ ਨੀਲਾ 6", - "228be6": "ਨੀਲਾ 6", - "15aabf": "ਫਿਰੋਜੀ 6", - "12b886": "ਟੀਲ 6", - "40c057": "ਹਰਾ 6", - "82c91e": "ਲਾਇਮ 6", - "fab005": "ਪੀਲਾ 6", - "fd7e14": "ਸੰਤਰੀ 6", - "000000": "ਕਾਲਾ", - "343a40": "ਸੁਰਮਈ 8", - "495057": "ਸੁਰਮਈ 7", - "c92a2a": "ਲਾਲ 9", - "a61e4d": "ਗੁਲਾਬੀ 9", - "862e9c": "ਅੰਗੂਰੀ 9", - "5f3dc4": "ਜਾਮਣੀ 9", - "364fc7": "ਗੂੜ੍ਹਾ ਨੀਲਾ 9", - "1864ab": "ਨੀਲਾ 9", - "0b7285": "ਫਿਰੋਜੀ 9", - "087f5b": "ਟੀਲ 9", - "2b8a3e": "ਹਰਾ 9", - "5c940d": "ਲਾਇਮ 9", - "e67700": "ਪੀਲਾ 9", - "d9480f": "ਸੰਤਰੀ 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/percentages.json b/src/locales/percentages.json index b80dce1b4..1619ae971 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -1,55 +1,55 @@ { - "ar-SA": 89, - "bg-BG": 54, - "bn-BD": 60, - "ca-ES": 97, - "cs-CZ": 74, - "da-DK": 33, - "de-DE": 100, - "el-GR": 97, + "ar-SA": 83, + "bg-BG": 57, + "bn-BD": 63, + "ca-ES": 92, + "cs-CZ": 67, + "da-DK": 35, + "de-DE": 94, + "el-GR": 92, "en": 100, - "es-ES": 98, - "eu-ES": 98, - "fa-IR": 98, - "fi-FI": 97, - "fr-FR": 98, - "gl-ES": 98, - "he-IL": 96, - "hi-IN": 72, - "hu-HU": 86, - "id-ID": 97, - "it-IT": 98, - "ja-JP": 98, - "kaa": 21, - "kab-KAB": 95, - "kk-KZ": 20, - "km-KH": 10, - "ko-KR": 100, - "ku-TR": 100, - "lt-LT": 63, - "lv-LV": 98, - "mr-IN": 98, - "my-MM": 40, - "nb-NO": 100, - "nl-NL": 93, - "nn-NO": 87, - "oc-FR": 96, - "pa-IN": 88, - "pl-PL": 89, - "pt-BR": 97, - "pt-PT": 98, - "ro-RO": 100, - "ru-RU": 100, - "si-LK": 8, - "sk-SK": 100, - "sl-SI": 100, - "sv-SE": 100, - "ta-IN": 92, + "es-ES": 93, + "eu-ES": 94, + "fa-IR": 93, + "fi-FI": 92, + "fr-FR": 93, + "gl-ES": 92, + "he-IL": 91, + "hi-IN": 74, + "hu-HU": 80, + "id-ID": 92, + "it-IT": 94, + "ja-JP": 92, + "kaa": 18, + "kab-KAB": 92, + "kk-KZ": 22, + "km-KH": 2, + "ko-KR": 94, + "ku-TR": 94, + "lt-LT": 59, + "lv-LV": 93, + "mr-IN": 93, + "my-MM": 43, + "nb-NO": 94, + "nl-NL": 87, + "nn-NO": 81, + "oc-FR": 91, + "pa-IN": 82, + "pl-PL": 83, + "pt-BR": 94, + "pt-PT": 93, + "ro-RO": 94, + "ru-RU": 94, + "si-LK": 9, + "sk-SK": 94, + "sl-SI": 94, + "sv-SE": 94, + "ta-IN": 86, "th-TH": 41, - "tr-TR": 96, - "uk-UA": 100, - "vi-VN": 57, - "zh-CN": 100, - "zh-HK": 26, - "zh-TW": 100 + "tr-TR": 91, + "uk-UA": 94, + "vi-VN": 59, + "zh-CN": 94, + "zh-HK": 27, + "zh-TW": 94 } diff --git a/src/locales/pl-PL.json b/src/locales/pl-PL.json index 047e5ec6b..e05fdc65c 100644 --- a/src/locales/pl-PL.json +++ b/src/locales/pl-PL.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "Biały", - "f8f9fa": "Szary 0", - "f1f3f5": "Szary 1", - "fff5f5": "Czerwony 0", - "fff0f6": "Różowy 0", - "f8f0fc": "Bordowy 0", - "f3f0ff": "Fioletowy 0", - "edf2ff": "Granatowy 0", - "e7f5ff": "Niebieski 0", - "e3fafc": "Błękitny 0", - "e6fcf5": "Turkusowy 0", - "ebfbee": "Zielony 0", - "f4fce3": "Limonkowy 0", - "fff9db": "Żółty 0", - "fff4e6": "Pomarańczowy 0", "transparent": "Przezroczysty", - "ced4da": "Szary 4", - "868e96": "Szary 6", - "fa5252": "Czerwony 6", - "e64980": "Różowy 6", - "be4bdb": "Bordowy 6", - "7950f2": "Fioletowy 6", - "4c6ef5": "Granatowy 6", - "228be6": "Niebieski 6", - "15aabf": "Błękitny 6", - "12b886": "Turkusowy 6", - "40c057": "Zielony 6", - "82c91e": "Limonkowy 6", - "fab005": "Żółty 6", - "fd7e14": "Pomarańczowy 6", - "000000": "Czarny", - "343a40": "Szary 8", - "495057": "Szary 7", - "c92a2a": "Czerwony 9", - "a61e4d": "Różowy 9", - "862e9c": "Bordowy 9", - "5f3dc4": "Fioletowy 9", - "364fc7": "Granatowy 9", - "1864ab": "Niebieski 9", - "0b7285": "Błękitny 9", - "087f5b": "Turkusowy 9", - "2b8a3e": "Zielony 9", - "5c940d": "Limonkowy 9", - "e67700": "Żółty 9", - "d9480f": "Pomarańczowy 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index bf4f7d445..30ae031d5 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -54,7 +54,7 @@ "veryLarge": "Muito grande", "solid": "Sólido", "hachure": "Hachura", - "zigzag": "", + "zigzag": "Zigue-zague", "crossHatch": "Hachura cruzada", "thin": "Fino", "bold": "Espesso", @@ -111,7 +111,7 @@ "increaseFontSize": "Aumentar o tamanho da fonte", "unbindText": "Desvincular texto", "bindText": "Vincular texto ao contêiner", - "createContainerFromText": "", + "createContainerFromText": "Envolver texto em um contêiner", "link": { "edit": "Editar link", "create": "Criar link", @@ -208,10 +208,10 @@ "collabSaveFailed": "Não foi possível salvar no banco de dados do servidor. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho.", "collabSaveFailed_sizeExceeded": "Não foi possível salvar no banco de dados do servidor, a tela parece ser muito grande. Se os problemas persistirem, salve o arquivo localmente para garantir que não perca o seu trabalho.", "brave_measure_text_error": { - "line1": "", - "line2": "", - "line3": "", - "line4": "" + "line1": "Parece que você está usando o navegador Brave com a configuração Bloquear Impressões Digitais no modo agressivo.", + "line2": "Isso pode acabar quebrando Elementos de Texto em seus desenhos.", + "line3": "Recomendamos fortemente desativar essa configuração. Você pode acessar o passo a passo sobre como fazer isso.", + "line4": "Se desativar essa configuração não corrigir a exibição de elementos de texto, por favor abra uma issue em nosso GitHub, ou mande uma mensagem em nosso Discord" } }, "toolBar": { @@ -306,8 +306,8 @@ "doubleClick": "clique duplo", "drag": "arrastar", "editor": "Editor", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Editar linha/ponta da seta", + "editText": "Editar texto / adicionar etiqueta", "github": "Encontrou algum problema? Nos informe", "howto": "Siga nossos guias", "or": "ou", @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Use {{shortcut}} para colar como um único elemento,\nou cole em um editor de texto já existente" }, "colors": { - "ffffff": "Braco", - "f8f9fa": "Cinza 0", - "f1f3f5": "Cinza 1", - "fff5f5": "Vermelho 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Uva 0", - "f3f0ff": "Violeta 0", - "edf2ff": "Índigo 0", - "e7f5ff": "Azul 0", - "e3fafc": "Ciano 0", - "e6fcf5": "Verde-azulado 0", - "ebfbee": "Verde 0", - "f4fce3": "Lima 0", - "fff9db": "Amarelo 0", - "fff4e6": "Laranja 0", "transparent": "Transparente", - "ced4da": "Cinza 4", - "868e96": "Cinza 6", - "fa5252": "Vermelho 6", - "e64980": "Rosa 6", - "be4bdb": "Uva 6", - "7950f2": "Violeta 6", - "4c6ef5": "Índigo 6", - "228be6": "Azul 6", - "15aabf": "Ciano 6", - "12b886": "Verde-azulado 6", - "40c057": "Verde 6", - "82c91e": "Lima 6", - "fab005": "Amarelo 6", - "fd7e14": "Laranja 6", - "000000": "Preto", - "343a40": "Cinza 8", - "495057": "Cinza 7", - "c92a2a": "Vermelho 9", - "a61e4d": "Rosa 9", - "862e9c": "Uva 9", - "5f3dc4": "Violeta 9", - "364fc7": "Índigo 9", - "1864ab": "Azul 9", - "0b7285": "Ciano 9", - "087f5b": "Verde-azulado 9", - "2b8a3e": "Verde 9", - "5c940d": "Lima 9", - "e67700": "Amarelo 9", - "d9480f": "Laranja 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Escolha uma ferramenta e comece a desenhar!", "helpHint": "Atalhos e ajuda" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/pt-PT.json b/src/locales/pt-PT.json index 0070d162c..943e5db3f 100644 --- a/src/locales/pt-PT.json +++ b/src/locales/pt-PT.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Usar {{shortcut}} para colar como um único elemento,\nou colar num editor de texto existente" }, "colors": { - "ffffff": "Branco", - "f8f9fa": "Cinza 0", - "f1f3f5": "Cinza 1", - "fff5f5": "Vermelho 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Uva 0", - "f3f0ff": "Violeta 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Azul 0", - "e3fafc": "Ciano 0", - "e6fcf5": "Verde-azulado 0", - "ebfbee": "Verde 0", - "f4fce3": "Lima 0", - "fff9db": "Amarelo 0", - "fff4e6": "Laranja 0", "transparent": "Transparente", - "ced4da": "Cinza 4", - "868e96": "Cinza 6", - "fa5252": "Vermelho 6", - "e64980": "Rosa 6", - "be4bdb": "Uva 6", - "7950f2": "Violeta 6", - "4c6ef5": "Indigo 6", - "228be6": "Azul 6", - "15aabf": "Ciano 6", - "12b886": "Verde-azulado 6", - "40c057": "Verde 6", - "82c91e": "Lima 6", - "fab005": "Amarelo 6", - "fd7e14": "Laranja 6", - "000000": "Preto", - "343a40": "Cinza 8", - "495057": "Cinza 7", - "c92a2a": "Vermelho 9", - "a61e4d": "Rosa 9", - "862e9c": "Uva 9", - "5f3dc4": "Violeta 9", - "364fc7": "Indigo 9", - "1864ab": "Azul 9", - "0b7285": "Ciano 9", - "087f5b": "Verde-azulado 9", - "2b8a3e": "Verde 9", - "5c940d": "Lima 9", - "e67700": "Amarelo 9", - "d9480f": "Laranja 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Escolha uma ferramenta e comece a desenhar!", "helpHint": "Atalhos e ajuda" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/ro-RO.json b/src/locales/ro-RO.json index 1f478f36a..5440f8f72 100644 --- a/src/locales/ro-RO.json +++ b/src/locales/ro-RO.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Folosește {{shortcut}} pentru a insera ca un singur element\nsau insera într-un editor de text existent" }, "colors": { - "ffffff": "Alb", - "f8f9fa": "Gri 0", - "f1f3f5": "Gri 1", - "fff5f5": "Roșu 0", - "fff0f6": "Roz 0", - "f8f0fc": "Struguriu 0", - "f3f0ff": "Violet 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Albastru 0", - "e3fafc": "Cyan 0", - "e6fcf5": "Cyan-verde", - "ebfbee": "Verde 0", - "f4fce3": "Verde-limetă", - "fff9db": "Galben 0", - "fff4e6": "Portocaliu 0", "transparent": "Transparent", - "ced4da": "Gri 4", - "868e96": "Gri 6", - "fa5252": "Roșu 6", - "e64980": "Roz 6", - "be4bdb": "Struguriu 6", - "7950f2": "Violet 6", - "4c6ef5": "Indigo 6", - "228be6": "Albastru 6", - "15aabf": "Cyan 6", - "12b886": "Cyan-verde 6", - "40c057": "Verde 6", - "82c91e": "Verde-limetă 6", - "fab005": "Galben 6", - "fd7e14": "Portocaliu 6", - "000000": "Negru", - "343a40": "Gri 8", - "495057": "Gri 7", - "c92a2a": "Roșu 9", - "a61e4d": "Roz 9", - "862e9c": "Struguriu 9", - "5f3dc4": "Violet 9", - "364fc7": "Indigo 9", - "1864ab": "Albastru 9", - "0b7285": "Cyan 9", - "087f5b": "Cyan-verde 9", - "2b8a3e": "Verde 9", - "5c940d": "Verde-limetă 9", - "e67700": "Galben 9", - "d9480f": "Portocaliu 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Alege un instrument și începe să desenezi!", "helpHint": "Comenzi rapide și ajutor" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json index c4680a7f6..7ba5b3374 100644 --- a/src/locales/ru-RU.json +++ b/src/locales/ru-RU.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Используйте {{shortcut}}, чтобы вставить один объект,\nили вставьте в существующий текстовый редактор" }, "colors": { - "ffffff": "Белый", - "f8f9fa": "Серый 0", - "f1f3f5": "Серый 1", - "fff5f5": "Красный 0", - "fff0f6": "Розовый 0", - "f8f0fc": "Виноградный 0", - "f3f0ff": "Фиолетовый 0", - "edf2ff": "Индиго 0", - "e7f5ff": "Синий 0", - "e3fafc": "Голубой 0", - "e6fcf5": "Бирюзовый 0", - "ebfbee": "Зелёный 0", - "f4fce3": "Лайм 0", - "fff9db": "Жёлтый 0", - "fff4e6": "Оранжевый 0", "transparent": "Прозрачный", - "ced4da": "Серый 4", - "868e96": "Серый 6", - "fa5252": "Красный 6", - "e64980": "Розовый 6", - "be4bdb": "Виноградный 6", - "7950f2": "Фиолетовый 6", - "4c6ef5": "Индиго 6", - "228be6": "Синий 6", - "15aabf": "Голубой 6", - "12b886": "Бирюзовый 6", - "40c057": "Зелёный 6", - "82c91e": "Лайм 6", - "fab005": "Жёлтый 6", - "fd7e14": "Оранжевый 6", - "000000": "Чёрный", - "343a40": "Серый 8", - "495057": "Серый 7", - "c92a2a": "Красный 9", - "a61e4d": "Розовый 9", - "862e9c": "Виноградный 9", - "5f3dc4": "Фиолетовый 9", - "364fc7": "Индиго 9", - "1864ab": "Синий 9", - "0b7285": "Голубой 9", - "087f5b": "Бирюзовый 9", - "2b8a3e": "Зелёный 9", - "5c940d": "Лайм 9", - "e67700": "Жёлтый 9", - "d9480f": "Оранжевый 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Выберите инструмент и начните рисовать!", "helpHint": "Сочетания клавиш и помощь" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/si-LK.json b/src/locales/si-LK.json index 60a3d2f1f..e3b5a5357 100644 --- a/src/locales/si-LK.json +++ b/src/locales/si-LK.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/sk-SK.json b/src/locales/sk-SK.json index 4e97ba73e..2123d7c1a 100644 --- a/src/locales/sk-SK.json +++ b/src/locales/sk-SK.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Použitím {{shortcut}} vložte ako samostatný prvok alebo vložte do existujúceho editovaného textu" }, "colors": { - "ffffff": "Biela", - "f8f9fa": "Sivá 0", - "f1f3f5": "Sivá 1", - "fff5f5": "Červená 0", - "fff0f6": "Ružová 0", - "f8f0fc": "Hroznová fialová 0", - "f3f0ff": "Fialová 0", - "edf2ff": "Tmavomodrá 0", - "e7f5ff": "Modrá 0", - "e3fafc": "Azúrová 0", - "e6fcf5": "Modrozelená 0", - "ebfbee": "Zelená 0", - "f4fce3": "Limetková 0", - "fff9db": "Žltá 0", - "fff4e6": "Oranžová 0", "transparent": "Priehľadná", - "ced4da": "Sivá 4", - "868e96": "Sivá 6", - "fa5252": "Červená 6", - "e64980": "Ružová 6", - "be4bdb": "Hroznová fialová 6", - "7950f2": "Fialová 6", - "4c6ef5": "Tmavomodrá 6", - "228be6": "Modrá 6", - "15aabf": "Azúrová 6", - "12b886": "Modrozelená 6", - "40c057": "Zelená 6", - "82c91e": "Limetková 6", - "fab005": "Žltá 6", - "fd7e14": "Oranžová 6", - "000000": "Čierna", - "343a40": "Sivá 8", - "495057": "Sivá 7", - "c92a2a": "Červená 9", - "a61e4d": "Ružová 9", - "862e9c": "Hroznová fialová 9", - "5f3dc4": "Fialová 9", - "364fc7": "Tmavomodrá 9", - "1864ab": "Modrá 9", - "0b7285": "Azúrová 9", - "087f5b": "Modrozelená 9", - "2b8a3e": "Zelená 9", - "5c940d": "Limetková 9", - "e67700": "Žltá 9", - "d9480f": "Oranžová 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Zvoľte nástroj a začnite kresliť!", "helpHint": "Klávesové skratky a pomocník" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/sl-SI.json b/src/locales/sl-SI.json index 1b5957384..902b2476f 100644 --- a/src/locales/sl-SI.json +++ b/src/locales/sl-SI.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Uporabite {{shortcut}}, da prilepite kot en element,\n ali prilepite v obstoječ urejevalnik besedil" }, "colors": { - "ffffff": "Bela", - "f8f9fa": "Siva 0", - "f1f3f5": "Siva 1", - "fff5f5": "Rdeča 0", - "fff0f6": "Roza 0", - "f8f0fc": "Grozdje 0", - "f3f0ff": "Vijolična 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Modra 0", - "e3fafc": "Cijan 0", - "e6fcf5": "Modrozelena 0", - "ebfbee": "Zelena 0", - "f4fce3": "Limeta 0", - "fff9db": "Rumena 0", - "fff4e6": "Oranžna 0", "transparent": "Prosojno", - "ced4da": "Siva 4", - "868e96": "Siva 6", - "fa5252": "Rdeča 6", - "e64980": "Roza 6", - "be4bdb": "Grozdje 6", - "7950f2": "Vijolična 6", - "4c6ef5": "Indigo 6", - "228be6": "Modra 6", - "15aabf": "Cijan 6", - "12b886": "Modrozelena 6", - "40c057": "Zelena 6", - "82c91e": "Limeta 6", - "fab005": "Rumena 6", - "fd7e14": "Oranžna 6", - "000000": "Črna", - "343a40": "Siva 8", - "495057": "Siva 7", - "c92a2a": "Rdeča 9", - "a61e4d": "Roza 9", - "862e9c": "Grozdje 9", - "5f3dc4": "Vijolična 9", - "364fc7": "Indigo 9", - "1864ab": "Modra 9", - "0b7285": "Cijan 9", - "087f5b": "Modrozelena 9", - "2b8a3e": "Zelena 9", - "5c940d": "Limeta 9", - "e67700": "Rumena 9", - "d9480f": "Oranžna 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Izberi orodje in začni z risanjem!", "helpHint": "Bližnjice in pomoč" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/sv-SE.json b/src/locales/sv-SE.json index a3d98d7a7..641e3ce66 100644 --- a/src/locales/sv-SE.json +++ b/src/locales/sv-SE.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Använd {{shortcut}} för att klistra in som ett enda element,\neller klistra in i en befintlig textredigerare" }, "colors": { - "ffffff": "Vit", - "f8f9fa": "Grå 0", - "f1f3f5": "Grå 1", - "fff5f5": "Röd 0", - "fff0f6": "Rosa 0", - "f8f0fc": "Lila 0", - "f3f0ff": "Violett 0", - "edf2ff": "Indigo 0", - "e7f5ff": "Blå 0", - "e3fafc": "Turkos 0", - "e6fcf5": "Blågrön 0", - "ebfbee": "Grön 0", - "f4fce3": "Limegrön 0", - "fff9db": "Gul 0", - "fff4e6": "Orange 0", "transparent": "Genomskinlig", - "ced4da": "Grå 4", - "868e96": "Grå 6", - "fa5252": "Röd 6", - "e64980": "Rosa 6", - "be4bdb": "Lila 6", - "7950f2": "Violett 6", - "4c6ef5": "Indigo 6", - "228be6": "Blå 6", - "15aabf": "Turkos 6", - "12b886": "Blågrön 6", - "40c057": "Grön 6", - "82c91e": "Limegrön 6", - "fab005": "Gul 6", - "fd7e14": "Orange 6", - "000000": "Svart", - "343a40": "Grå 8", - "495057": "Grå 7", - "c92a2a": "Röd 9", - "a61e4d": "Rosa 9", - "862e9c": "Lila 9", - "5f3dc4": "Violett 9", - "364fc7": "Indigo 9", - "1864ab": "Blå 9", - "0b7285": "Turkos 9", - "087f5b": "Blågrön 9", - "2b8a3e": "Grön 9", - "5c940d": "Limegrön 9", - "e67700": "Gul 9", - "d9480f": "Orange 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Välj ett verktyg & börja rita!", "helpHint": "Genvägar & hjälp" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/ta-IN.json b/src/locales/ta-IN.json index b82220f4a..640334e97 100644 --- a/src/locales/ta-IN.json +++ b/src/locales/ta-IN.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "வெள்ளை", - "f8f9fa": "சாம்பல்நிறம் 0", - "f1f3f5": "சாம்பல்நிறம் 1", - "fff5f5": "சிகப்பு 0", - "fff0f6": "இளஞ்சிவப்பு 0", - "f8f0fc": "திராட்சை 0", - "f3f0ff": "ஊதா 0", - "edf2ff": "கருநீலம் 0", - "e7f5ff": "நீலம் 0", - "e3fafc": "மயில்நிறம் 0", - "e6fcf5": "டீல் 0", - "ebfbee": "பச்சை 0", - "f4fce3": "தேசிக்காய்நிறம் 0", - "fff9db": "மஞ்சள் 0", - "fff4e6": "ஆரஞ்சு 0", "transparent": "ஒளிபுகுத்தன்மை", - "ced4da": "சாம்பல்நிறம் 4", - "868e96": "சாம்பல்நிறம் 6", - "fa5252": "சிகப்பு 6", - "e64980": "இளஞ்சிவப்பு 6", - "be4bdb": "திராட்சை 6", - "7950f2": "ஊதா 6", - "4c6ef5": "கருநீலம் 6", - "228be6": "நீலம் 6", - "15aabf": "மயில்நிறம் 6", - "12b886": "டீல் 6", - "40c057": "பச்சை 6", - "82c91e": "தேசிக்காய்நிறம் 6", - "fab005": "மஞ்சள் 6", - "fd7e14": "ஆரஞ்சு 6", - "000000": "கருப்பு", - "343a40": "சாம்பல்நிறம் 8", - "495057": "சாம்பல்நிறம் 7", - "c92a2a": "சிகப்பு 9", - "a61e4d": "இளஞ்சிவப்பு 9", - "862e9c": "திராட்சை 9", - "5f3dc4": "ஊதா 9", - "364fc7": "கருநீலம் 9", - "1864ab": "நீலம் 9", - "0b7285": "மயில்நிறம் 9", - "087f5b": "டீல் 9", - "2b8a3e": "பச்சை 9", - "5c940d": "தேசிக்காய்நிறம் 9", - "e67700": "மஞ்சள் 9", - "d9480f": "ஆரஞ்சு 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "கருவியைத் தேர்ந்தெடு & வரை!", "helpHint": "குறுக்குவழிகள் & உதவி" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/th-TH.json b/src/locales/th-TH.json index 3860af21d..e7ca29d25 100644 --- a/src/locales/th-TH.json +++ b/src/locales/th-TH.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "สีขาว", - "f8f9fa": "สีเทา 0", - "f1f3f5": "สีเทา 1", - "fff5f5": "สีแดง 0", - "fff0f6": "สีชมพู 0", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "สีเทา 4", - "868e96": "สีเทา 6", - "fa5252": "สีแดง 6", - "e64980": "สีชมพู 6", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/tr-TR.json b/src/locales/tr-TR.json index a48a16408..102273797 100644 --- a/src/locales/tr-TR.json +++ b/src/locales/tr-TR.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Tekil obje olarak yapıştırmak için veya var olan bir metin editörüne yapıştırmak için {{shortcut}} kullanın" }, "colors": { - "ffffff": "Beyaz", - "f8f9fa": "Gri 0", - "f1f3f5": "Gri 1", - "fff5f5": "Kırmızı 0", - "fff0f6": "Pembe 0", - "f8f0fc": "Koyu Mor 0", - "f3f0ff": "Mor 0", - "edf2ff": "Çivit 0", - "e7f5ff": "Mavi 0", - "e3fafc": "Camgöbeği 0", - "e6fcf5": "Deniz Mavisi 0", - "ebfbee": "Yeşil 0", - "f4fce3": "Yeşil 0", - "fff9db": "Sarı 0", - "fff4e6": "Turuncu 0", "transparent": "Şeffaf", - "ced4da": "Gri 4", - "868e96": "Gri 6", - "fa5252": "Kırmızı 6", - "e64980": "Pembe 6", - "be4bdb": "Koyu Mor 6", - "7950f2": "Mor 6", - "4c6ef5": "Çivit 6", - "228be6": "Mavi 6", - "15aabf": "Camgöbeği 6", - "12b886": "Deniz Mavisi 6", - "40c057": "Yeşil 6", - "82c91e": "Green 6", - "fab005": "Sarı 6", - "fd7e14": "Turuncu 6", - "000000": "Siyah", - "343a40": "Gri 8", - "495057": "Gri 7", - "c92a2a": "Kırmızı 9", - "a61e4d": "Pembe 9", - "862e9c": "Koyu Mor 9", - "5f3dc4": "Mor 9", - "364fc7": "Çivit 9", - "1864ab": "Mavi 9", - "0b7285": "Camgöbeği 9", - "087f5b": "Deniz Mavisi 9", - "2b8a3e": "Yeşil 9", - "5c940d": "Yeşil 9", - "e67700": "Sarı 9", - "d9480f": "Turuncu 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Bir araç seçin ve çizime başlayın!", "helpHint": "Kısayollar & yardım" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/uk-UA.json b/src/locales/uk-UA.json index a070cde6d..53dd31d55 100644 --- a/src/locales/uk-UA.json +++ b/src/locales/uk-UA.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "Використайте {{shortcut}} для вставки самостійного зразка або використайте в текстовому редакторі" }, "colors": { - "ffffff": "Білий", - "f8f9fa": "Сірий 0", - "f1f3f5": "Сірий 1", - "fff5f5": "Червоний 0", - "fff0f6": "Рожевий 0", - "f8f0fc": "Виноград 0", - "f3f0ff": "Фіолетовий 0", - "edf2ff": "Індиго 0", - "e7f5ff": "Синій 0", - "e3fafc": "Ціан 0", - "e6fcf5": "Зеленувато-блакитний 0", - "ebfbee": "Зелений 0", - "f4fce3": "Лайм 0", - "fff9db": "Жовтий 0", - "fff4e6": "Помаранчевий 0", "transparent": "Прозорий", - "ced4da": "Сірий 4", - "868e96": "Сірий 6", - "fa5252": "Червоний 6", - "e64980": "Рожевий 6", - "be4bdb": "Виноград 6", - "7950f2": "Фіолетовий 6", - "4c6ef5": "Індиго 6", - "228be6": "Синій 6", - "15aabf": "Ціан 6", - "12b886": "Зеленувато-блакитний 6", - "40c057": "Зелений 6", - "82c91e": "Лайм 6", - "fab005": "Жовтий 6", - "fd7e14": "Помаранчевий 6", - "000000": "Чорний", - "343a40": "Сірий 8", - "495057": "Сірий 7", - "c92a2a": "Червоний 9", - "a61e4d": "Рожевий 9", - "862e9c": "Виноград 9", - "5f3dc4": "Фіолетовий 9", - "364fc7": "Індиго 9", - "1864ab": "Синій 9", - "0b7285": "Ціан 9", - "087f5b": "Зеленувато-блакитний 9", - "2b8a3e": "Зелений 9", - "5c940d": "Лаймовий 9", - "e67700": "Жовтий 9", - "d9480f": "Помаранчевий 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "Оберіть інструмент і почніть малювати!", "helpHint": "Гарячі клавіші і допомога" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/vi-VN.json b/src/locales/vi-VN.json index 1015b0393..63a4cd68c 100644 --- a/src/locales/vi-VN.json +++ b/src/locales/vi-VN.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "Chàm 9", - "1864ab": "Xanh Dương 9", - "0b7285": "Lục Lam 9", - "087f5b": "Xanh Mòng Két 9", - "2b8a3e": "Xanh Lá 9", - "5c940d": "Chanh Xanh 9", - "e67700": "Vàng 9", - "d9480f": "Cam 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 08e0a8379..93ad2c948 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "使用 {{shortcut}} 粘贴为单个元素,\n或粘贴到现有的文本编辑器里" }, "colors": { - "ffffff": "白", - "f8f9fa": "灰 0", - "f1f3f5": "灰 1", - "fff5f5": "红 0", - "fff0f6": "粉红 0", - "f8f0fc": "紫红 0", - "f3f0ff": "蓝紫 0", - "edf2ff": "靛蓝 0", - "e7f5ff": "蓝 0", - "e3fafc": "青 0", - "e6fcf5": "蓝绿 0", - "ebfbee": "绿 0", - "f4fce3": "柠檬绿 0", - "fff9db": "黄 0", - "fff4e6": "橙 0", "transparent": "透明", - "ced4da": "灰 4", - "868e96": "灰 6", - "fa5252": "红 6", - "e64980": "粉红 6", - "be4bdb": "紫红 6", - "7950f2": "蓝紫 6", - "4c6ef5": "靛蓝 6", - "228be6": "蓝 6", - "15aabf": "青 6", - "12b886": "蓝绿 6", - "40c057": "绿 6", - "82c91e": "柠檬绿 6", - "fab005": "黄 6", - "fd7e14": "橙 6", - "000000": "黑", - "343a40": "灰 8", - "495057": "灰 7", - "c92a2a": "红 9", - "a61e4d": "粉红 9", - "862e9c": "紫红 9", - "5f3dc4": "蓝紫 9", - "364fc7": "靛蓝 9", - "1864ab": "蓝 9", - "0b7285": "青 9", - "087f5b": "蓝绿 9", - "2b8a3e": "绿 9", - "5c940d": "柠檬绿 9", - "e67700": "黄 9", - "d9480f": "橙 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "选择工具并开始绘图!", "helpHint": "快捷键和帮助" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/zh-HK.json b/src/locales/zh-HK.json index 527937163..6d03449d1 100644 --- a/src/locales/zh-HK.json +++ b/src/locales/zh-HK.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "" }, "colors": { - "ffffff": "", - "f8f9fa": "", - "f1f3f5": "", - "fff5f5": "", - "fff0f6": "", - "f8f0fc": "", - "f3f0ff": "", - "edf2ff": "", - "e7f5ff": "", - "e3fafc": "", - "e6fcf5": "", - "ebfbee": "", - "f4fce3": "", - "fff9db": "", - "fff4e6": "", "transparent": "", - "ced4da": "", - "868e96": "", - "fa5252": "", - "e64980": "", - "be4bdb": "", - "7950f2": "", - "4c6ef5": "", - "228be6": "", - "15aabf": "", - "12b886": "", - "40c057": "", - "82c91e": "", - "fab005": "", - "fd7e14": "", - "000000": "", - "343a40": "", - "495057": "", - "c92a2a": "", - "a61e4d": "", - "862e9c": "", - "5f3dc4": "", - "364fc7": "", - "1864ab": "", - "0b7285": "", - "087f5b": "", - "2b8a3e": "", - "5c940d": "", - "e67700": "", - "d9480f": "" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "", "helpHint": "" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 08965de95..3be58ef56 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -394,51 +394,21 @@ "pasteAsSingleElement": "使用 {{shortcut}} 以做為單一物件貼上,\n或貼上至現有的文字編輯器" }, "colors": { - "ffffff": "白", - "f8f9fa": "灰 0", - "f1f3f5": "灰 1", - "fff5f5": "紅 0", - "fff0f6": "粉紅 0", - "f8f0fc": "深紫 0", - "f3f0ff": "藍紫 0", - "edf2ff": "靛藍 0", - "e7f5ff": "藍 0", - "e3fafc": "青 0", - "e6fcf5": "藍綠 0", - "ebfbee": "綠 0", - "f4fce3": "黃綠 0", - "fff9db": "黃 0", - "fff4e6": "橘 0", "transparent": "透明", - "ced4da": "灰 4", - "868e96": "灰 6", - "fa5252": "紅 6", - "e64980": "粉紅 6", - "be4bdb": "深紫 6", - "7950f2": "藍紫 6", - "4c6ef5": "靛藍 6", - "228be6": "藍 6", - "15aabf": "青 6", - "12b886": "藍綠 6", - "40c057": "綠 6", - "82c91e": "黃綠 6", - "fab005": "黃 6", - "fd7e14": "橘 6", - "000000": "黑", - "343a40": "灰 8", - "495057": "灰 7", - "c92a2a": "紅 9", - "a61e4d": "粉紅 9", - "862e9c": "深紫 9", - "5f3dc4": "藍紫 9", - "364fc7": "靛藍 9", - "1864ab": "藍 9", - "0b7285": "青 9", - "087f5b": "藍綠 9", - "2b8a3e": "綠 9", - "5c940d": "黃綠 9", - "e67700": "黃 9", - "d9480f": "橘 9" + "black": "", + "white": "", + "red": "", + "pink": "", + "grape": "", + "violet": "", + "gray": "", + "blue": "", + "cyan": "", + "teal": "", + "green": "", + "yellow": "", + "orange": "", + "bronze": "" }, "welcomeScreen": { "app": { @@ -452,5 +422,12 @@ "toolbarHint": "選個工具開始畫圖吧!", "helpHint": "快速鍵與說明" } + }, + "colorPicker": { + "mostUsedCustomColors": "", + "colors": "", + "shades": "", + "hexCode": "", + "noShades": "" } } From a8f0a14610da74060592dec8f1171cb2cf42dd37 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Fri, 19 May 2023 15:47:01 +0200 Subject: [PATCH 075/451] fix: `withInternalFallback` leaking state in multi-instance scenarios (#6602) --- .../hoc/withInternalFallback.test.tsx | 100 ++++++++++++++++++ src/components/hoc/withInternalFallback.tsx | 43 ++++---- 2 files changed, 125 insertions(+), 18 deletions(-) create mode 100644 src/components/hoc/withInternalFallback.test.tsx diff --git a/src/components/hoc/withInternalFallback.test.tsx b/src/components/hoc/withInternalFallback.test.tsx new file mode 100644 index 000000000..af43db58a --- /dev/null +++ b/src/components/hoc/withInternalFallback.test.tsx @@ -0,0 +1,100 @@ +import { render, queryAllByTestId } from "../../tests/test-utils"; +import { Excalidraw, MainMenu } from "../../packages/excalidraw/index"; + +describe("Test internal component fallback rendering", () => { + it("should render only one menu per excalidraw instance (custom menu first scenario)", async () => { + const { container } = await render( +
+ + test + + +
, + ); + + expect(queryAllByTestId(container, "dropdown-menu-button")?.length).toBe(2); + + const excalContainers = container.querySelectorAll( + ".excalidraw-container", + ); + + expect( + queryAllByTestId(excalContainers[0], "dropdown-menu-button")?.length, + ).toBe(1); + expect( + queryAllByTestId(excalContainers[1], "dropdown-menu-button")?.length, + ).toBe(1); + }); + + it("should render only one menu per excalidraw instance (default menu first scenario)", async () => { + const { container } = await render( +
+ + + test + +
, + ); + + expect(queryAllByTestId(container, "dropdown-menu-button")?.length).toBe(2); + + const excalContainers = container.querySelectorAll( + ".excalidraw-container", + ); + + expect( + queryAllByTestId(excalContainers[0], "dropdown-menu-button")?.length, + ).toBe(1); + expect( + queryAllByTestId(excalContainers[1], "dropdown-menu-button")?.length, + ).toBe(1); + }); + + it("should render only one menu per excalidraw instance (two custom menus scenario)", async () => { + const { container } = await render( +
+ + test + + + test + +
, + ); + + expect(queryAllByTestId(container, "dropdown-menu-button")?.length).toBe(2); + + const excalContainers = container.querySelectorAll( + ".excalidraw-container", + ); + + expect( + queryAllByTestId(excalContainers[0], "dropdown-menu-button")?.length, + ).toBe(1); + expect( + queryAllByTestId(excalContainers[1], "dropdown-menu-button")?.length, + ).toBe(1); + }); + + it("should render only one menu per excalidraw instance (two default menus scenario)", async () => { + const { container } = await render( +
+ + +
, + ); + + expect(queryAllByTestId(container, "dropdown-menu-button")?.length).toBe(2); + + const excalContainers = container.querySelectorAll( + ".excalidraw-container", + ); + + expect( + queryAllByTestId(excalContainers[0], "dropdown-menu-button")?.length, + ).toBe(1); + expect( + queryAllByTestId(excalContainers[1], "dropdown-menu-button")?.length, + ).toBe(1); + }); +}); diff --git a/src/components/hoc/withInternalFallback.tsx b/src/components/hoc/withInternalFallback.tsx index 581a1874f..4131c51ec 100644 --- a/src/components/hoc/withInternalFallback.tsx +++ b/src/components/hoc/withInternalFallback.tsx @@ -1,5 +1,5 @@ import { atom, useAtom } from "jotai"; -import React, { useLayoutEffect } from "react"; +import React, { useLayoutEffect, useRef } from "react"; import { useTunnels } from "../../context/tunnels"; export const withInternalFallback = ( @@ -7,13 +7,6 @@ export const withInternalFallback = ( Component: React.FC

, ) => { const renderAtom = atom(0); - // flag set on initial render to tell the fallback component to skip the - // render until mount counter are initialized. This is because the counter - // is initialized in an effect, and thus we could end rendering both - // components at the same time until counter is initialized. - let preferHost = false; - - let counter = 0; const WrapperComponent: React.FC< P & { @@ -21,38 +14,52 @@ export const withInternalFallback = ( } > = (props) => { const { jotaiScope } = useTunnels(); - const [, setRender] = useAtom(renderAtom, jotaiScope); + // for rerenders + const [, setCounter] = useAtom(renderAtom, jotaiScope); + // for initial & subsequent renders. Tracked as component state + // due to excalidraw multi-instance scanerios. + const metaRef = useRef({ + // flag set on initial render to tell the fallback component to skip the + // render until mount counter are initialized. This is because the counter + // is initialized in an effect, and thus we could end rendering both + // components at the same time until counter is initialized. + preferHost: false, + counter: 0, + }); useLayoutEffect(() => { - setRender((c) => { + const meta = metaRef.current; + setCounter((c) => { const next = c + 1; - counter = next; + meta.counter = next; return next; }); return () => { - setRender((c) => { + setCounter((c) => { const next = c - 1; - counter = next; + meta.counter = next; if (!next) { - preferHost = false; + meta.preferHost = false; } return next; }); }; - }, [setRender]); + }, [setCounter]); if (!props.__fallback) { - preferHost = true; + metaRef.current.preferHost = true; } // ensure we don't render fallback and host components at the same time if ( // either before the counters are initialized - (!counter && props.__fallback && preferHost) || + (!metaRef.current.counter && + props.__fallback && + metaRef.current.preferHost) || // or after the counters are initialized, and both are rendered // (this is the default when host renders as well) - (counter > 1 && props.__fallback) + (metaRef.current.counter > 1 && props.__fallback) ) { return null; } From a4f05339aa0cbaecdb619f3de11f5e40d8c37e3e Mon Sep 17 00:00:00 2001 From: Rounik Prashar <56750020+irounik@users.noreply.github.com> Date: Wed, 24 May 2023 02:07:19 +0530 Subject: [PATCH 076/451] fix: Library dropdown visibility issue for mobile (#6613) Fix: Library dropdown visibility issue for mobile Co-authored-by: Rounik Prashar --- src/components/dropdownMenu/DropdownMenu.scss | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/dropdownMenu/DropdownMenu.scss b/src/components/dropdownMenu/DropdownMenu.scss index ff94f4920..6e628736f 100644 --- a/src/components/dropdownMenu/DropdownMenu.scss +++ b/src/components/dropdownMenu/DropdownMenu.scss @@ -11,8 +11,6 @@ top: auto; left: 0; width: 100%; - display: flex; - flex-direction: column; row-gap: 0.75rem; .dropdown-menu-container { From 7340c70a0697bcdafe3eebab33ffecb116c8bc5f Mon Sep 17 00:00:00 2001 From: Arnost Pleskot Date: Wed, 24 May 2023 16:40:20 +0200 Subject: [PATCH 077/451] perf: improve rendering performance for Library (#6587) * perf: improve rendering performance for Library * fix: return onDrag and onToggle functionality to Library Items * perf: cache exportToSvg output * fix: lint warning * fix: add onClick handler into LibraryUnit * feat: better spinner * fix: useCallback for getInsertedElements to fix linter error * feat: different batch size when svgs are cached * fix: library items alignment in row * feat: skeleton instead of spinner * fix: remove unused variables * feat: use css vars instead of hadcoded colors * feat: reverting skeleton, removing spinner * cleanup and unrelated refactor * change ROWS_RENDERED_PER_BATCH to 6 --------- Co-authored-by: dwelle --- src/components/LibraryMenu.tsx | 17 +- src/components/LibraryMenuItems.tsx | 246 ++++++++++---------------- src/components/LibraryMenuSection.tsx | 110 ++++++++++++ src/components/LibraryUnit.tsx | 27 +-- src/components/Spinner.scss | 1 + src/components/Spinner.tsx | 15 +- src/hooks/useLibraryItemSvg.ts | 59 ++++++ 7 files changed, 295 insertions(+), 180 deletions(-) create mode 100644 src/components/LibraryMenuSection.tsx create mode 100644 src/hooks/useLibraryItemSvg.ts diff --git a/src/components/LibraryMenu.tsx b/src/components/LibraryMenu.tsx index 0101d0cb5..a49f31970 100644 --- a/src/components/LibraryMenu.tsx +++ b/src/components/LibraryMenu.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback } from "react"; +import React, { useCallback } from "react"; import Library, { distributeLibraryItemsOnSquareGrid, libraryItemsAtom, @@ -43,8 +43,6 @@ export const LibraryMenuContent = ({ library, id, appState, - selectedItems, - onSelectItems, }: { pendingElements: LibraryItem["elements"]; onInsertLibraryItems: (libraryItems: LibraryItems) => void; @@ -54,8 +52,6 @@ export const LibraryMenuContent = ({ library: Library; id: string; appState: UIAppState; - selectedItems: LibraryItem["id"][]; - onSelectItems: (id: LibraryItem["id"][]) => void; }) => { const [libraryItemsData] = useAtom(libraryItemsAtom, jotaiScope); @@ -113,8 +109,6 @@ export const LibraryMenuContent = ({ } onInsertLibraryItems={onInsertLibraryItems} pendingElements={pendingElements} - selectedItems={selectedItems} - onSelectItems={onSelectItems} id={id} libraryReturnUrl={libraryReturnUrl} theme={appState.theme} @@ -143,9 +137,8 @@ export const LibraryMenu = () => { const setAppState = useExcalidrawSetAppState(); const elements = useExcalidrawElements(); - const [selectedItems, setSelectedItems] = useState([]); - - const deselectItems = useCallback(() => { + const onAddToLibrary = useCallback(() => { + // deselect canvas elements setAppState({ selectedElementIds: {}, selectedGroupIds: {}, @@ -158,14 +151,12 @@ export const LibraryMenu = () => { onInsertLibraryItems={(libraryItems) => { onInsertElements(distributeLibraryItemsOnSquareGrid(libraryItems)); }} - onAddToLibrary={deselectItems} + onAddToLibrary={onAddToLibrary} setAppState={setAppState} libraryReturnUrl={appProps.libraryReturnUrl} library={library} id={id} appState={appState} - selectedItems={selectedItems} - onSelectItems={setSelectedItems} /> ); }; diff --git a/src/components/LibraryMenuItems.tsx b/src/components/LibraryMenuItems.tsx index 0f4dda589..74f295cd4 100644 --- a/src/components/LibraryMenuItems.tsx +++ b/src/components/LibraryMenuItems.tsx @@ -1,6 +1,5 @@ -import React, { useState } from "react"; +import React, { useCallback, useState } from "react"; import { serializeLibraryAsJSON } from "../data/json"; -import { ExcalidrawElement, NonDeleted } from "../element/types"; import { t } from "../i18n"; import { ExcalidrawProps, @@ -8,27 +7,23 @@ import { LibraryItems, UIAppState, } from "../types"; -import { arrayToMap, chunk } from "../utils"; -import { LibraryUnit } from "./LibraryUnit"; +import { arrayToMap } from "../utils"; import Stack from "./Stack"; import { MIME_TYPES } from "../constants"; import Spinner from "./Spinner"; import { duplicateElements } from "../element/newElement"; import { LibraryMenuControlButtons } from "./LibraryMenuControlButtons"; import { LibraryDropdownMenu } from "./LibraryMenuHeaderContent"; +import LibraryMenuSection from "./LibraryMenuSection"; import "./LibraryMenuItems.scss"; -const CELLS_PER_ROW = 4; - -const LibraryMenuItems = ({ +export default function LibraryMenuItems({ isLoading, libraryItems, onAddToLibrary, onInsertLibraryItems, pendingElements, - selectedItems, - onSelectItems, theme, id, libraryReturnUrl, @@ -38,12 +33,26 @@ const LibraryMenuItems = ({ pendingElements: LibraryItem["elements"]; onInsertLibraryItems: (libraryItems: LibraryItems) => void; onAddToLibrary: (elements: LibraryItem["elements"]) => void; - selectedItems: LibraryItem["id"][]; - onSelectItems: (id: LibraryItem["id"][]) => void; libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"]; theme: UIAppState["theme"]; id: string; -}) => { +}) { + const [selectedItems, setSelectedItems] = useState([]); + + const unpublishedItems = libraryItems.filter( + (item) => item.status !== "published", + ); + const publishedItems = libraryItems.filter( + (item) => item.status === "published", + ); + + const showBtn = !libraryItems.length && !pendingElements.length; + + const isLibraryEmpty = + !pendingElements.length && + !unpublishedItems.length && + !publishedItems.length; + const [lastSelectedItem, setLastSelectedItem] = useState< LibraryItem["id"] | null >(null); @@ -64,7 +73,7 @@ const LibraryMenuItems = ({ const rangeEnd = orderedItems.findIndex((item) => item.id === id); if (rangeStart === -1 || rangeEnd === -1) { - onSelectItems([...selectedItems, id]); + setSelectedItems([...selectedItems, id]); return; } @@ -82,136 +91,69 @@ const LibraryMenuItems = ({ [], ); - onSelectItems(nextSelectedIds); + setSelectedItems(nextSelectedIds); } else { - onSelectItems([...selectedItems, id]); + setSelectedItems([...selectedItems, id]); } setLastSelectedItem(id); } else { setLastSelectedItem(null); - onSelectItems(selectedItems.filter((_id) => _id !== id)); + setSelectedItems(selectedItems.filter((_id) => _id !== id)); } }; - const getInsertedElements = (id: string) => { - let targetElements; - if (selectedItems.includes(id)) { - targetElements = libraryItems.filter((item) => - selectedItems.includes(item.id), - ); - } else { - targetElements = libraryItems.filter((item) => item.id === id); - } - return targetElements.map((item) => { - return { - ...item, - // duplicate each library item before inserting on canvas to confine - // ids and bindings to each library item. See #6465 - elements: duplicateElements(item.elements, { randomizeSeed: true }), - }; - }); - }; + const getInsertedElements = useCallback( + (id: string) => { + let targetElements; + if (selectedItems.includes(id)) { + targetElements = libraryItems.filter((item) => + selectedItems.includes(item.id), + ); + } else { + targetElements = libraryItems.filter((item) => item.id === id); + } + return targetElements.map((item) => { + return { + ...item, + // duplicate each library item before inserting on canvas to confine + // ids and bindings to each library item. See #6465 + elements: duplicateElements(item.elements, { randomizeSeed: true }), + }; + }); + }, + [libraryItems, selectedItems], + ); - const createLibraryItemCompo = (params: { - item: - | LibraryItem - | /* pending library item */ { - id: null; - elements: readonly NonDeleted[]; - } - | null; - onClick?: () => void; - key: string; - }) => { - return ( - - {})} - id={params.item?.id || null} - selected={!!params.item?.id && selectedItems.includes(params.item.id)} - onToggle={onItemSelectToggle} - onDrag={(id, event) => { - event.dataTransfer.setData( - MIME_TYPES.excalidrawlib, - serializeLibraryAsJSON(getInsertedElements(id)), - ); - }} - /> - + const onItemDrag = (id: LibraryItem["id"], event: React.DragEvent) => { + event.dataTransfer.setData( + MIME_TYPES.excalidrawlib, + serializeLibraryAsJSON(getInsertedElements(id)), ); }; - const renderLibrarySection = ( - items: ( - | LibraryItem - | /* pending library item */ { - id: null; - elements: readonly NonDeleted[]; - } - )[], - ) => { - const _items = items.map((item) => { - if (item.id) { - return createLibraryItemCompo({ - item, - onClick: () => onInsertLibraryItems(getInsertedElements(item.id)), - key: item.id, - }); - } - return createLibraryItemCompo({ - key: "__pending__item__", - item, - onClick: () => onAddToLibrary(pendingElements), - }); - }); - - // ensure we render all empty cells if no items are present - let rows = chunk(_items, CELLS_PER_ROW); - if (!rows.length) { - rows = [[]]; + const isItemSelected = (id: LibraryItem["id"] | null) => { + if (!id) { + return false; } - return rows.map((rowItems, index, rows) => { - if (index === rows.length - 1) { - // pad row with empty cells - rowItems = rowItems.concat( - new Array(CELLS_PER_ROW - rowItems.length) - .fill(null) - .map((_, index) => { - return createLibraryItemCompo({ - key: `empty_${index}`, - item: null, - }); - }), - ); - } - return ( - - {rowItems} - - ); - }); + return selectedItems.includes(id); }; - const unpublishedItems = libraryItems.filter( - (item) => item.status !== "published", + const onItemClick = useCallback( + (id: LibraryItem["id"] | null) => { + if (!id) { + onAddToLibrary(pendingElements); + } else { + onInsertLibraryItems(getInsertedElements(id)); + } + }, + [ + getInsertedElements, + onAddToLibrary, + onInsertLibraryItems, + pendingElements, + ], ); - const publishedItems = libraryItems.filter( - (item) => item.status === "published", - ); - - const showBtn = !libraryItems.length && !pendingElements.length; - - const isLibraryEmpty = - !pendingElements.length && - !unpublishedItems.length && - !publishedItems.length; return (

)} @@ -258,28 +200,32 @@ const LibraryMenuItems = ({
)} -
- {!pendingElements.length && !unpublishedItems.length ? ( -
-
- {t("library.noItems")} -
-
- {publishedItems.length > 0 - ? t("library.hint_emptyPrivateLibrary") - : t("library.hint_emptyLibrary")} -
+ {!pendingElements.length && !unpublishedItems.length ? ( +
+
+ {t("library.noItems")}
- ) : ( - renderLibrarySection([ +
+ {publishedItems.length > 0 + ? t("library.hint_emptyPrivateLibrary") + : t("library.hint_emptyLibrary")} +
+
+ ) : ( + + ]} + onItemSelectToggle={onItemSelectToggle} + onItemDrag={onItemDrag} + onClick={onItemClick} + isItemSelected={isItemSelected} + /> + )} <> @@ -291,7 +237,13 @@ const LibraryMenuItems = ({
)} {publishedItems.length > 0 ? ( - renderLibrarySection(publishedItems) + ) : unpublishedItems.length > 0 ? (
)}
); -}; - -export default LibraryMenuItems; +} diff --git a/src/components/LibraryMenuSection.tsx b/src/components/LibraryMenuSection.tsx new file mode 100644 index 000000000..d1af85481 --- /dev/null +++ b/src/components/LibraryMenuSection.tsx @@ -0,0 +1,110 @@ +import React, { useEffect, useMemo, useState, useTransition } from "react"; +import { LibraryUnit } from "./LibraryUnit"; +import { LibraryItem } from "../types"; +import Stack from "./Stack"; +import clsx from "clsx"; +import { ExcalidrawElement, NonDeleted } from "../element/types"; +import { useAtom } from "jotai"; +import { libraryItemSvgsCache } from "../hooks/useLibraryItemSvg"; + +const ITEMS_PER_ROW = 4; +const ROWS_RENDERED_PER_BATCH = 6; +const CACHED_ROWS_RENDERED_PER_BATCH = 16; + +type LibraryOrPendingItem = ( + | LibraryItem + | /* pending library item */ { + id: null; + elements: readonly NonDeleted[]; + } +)[]; + +interface Props { + items: LibraryOrPendingItem; + onClick: (id: LibraryItem["id"] | null) => void; + onItemSelectToggle: (id: LibraryItem["id"], event: React.MouseEvent) => void; + onItemDrag: (id: LibraryItem["id"], event: React.DragEvent) => void; + isItemSelected: (id: LibraryItem["id"] | null) => boolean; +} + +function LibraryRow({ + items, + onItemSelectToggle, + onItemDrag, + isItemSelected, + onClick, +}: Props) { + return ( + + {items.map((item) => ( + + + + ))} + + ); +} + +const EmptyLibraryRow = () => ( + + +
+ + +); + +function LibraryMenuSection({ + items, + onItemSelectToggle, + onItemDrag, + isItemSelected, + onClick, +}: Props) { + const rows = Math.ceil(items.length / ITEMS_PER_ROW); + const [, startTransition] = useTransition(); + const [index, setIndex] = useState(0); + const [svgCache] = useAtom(libraryItemSvgsCache); + + const rowsRenderedPerBatch = useMemo(() => { + return svgCache.size === 0 + ? ROWS_RENDERED_PER_BATCH + : CACHED_ROWS_RENDERED_PER_BATCH; + }, [svgCache]); + + useEffect(() => { + if (index < rows) { + startTransition(() => { + setIndex(index + rowsRenderedPerBatch); + }); + } + }, [index, rows, startTransition, rowsRenderedPerBatch]); + + return ( + <> + {Array.from({ length: rows }).map((_, i) => + i < index ? ( + + ) : ( + + ), + )} + + ); +} + +export default LibraryMenuSection; diff --git a/src/components/LibraryUnit.tsx b/src/components/LibraryUnit.tsx index 7e8181d7b..68fdec143 100644 --- a/src/components/LibraryUnit.tsx +++ b/src/components/LibraryUnit.tsx @@ -1,12 +1,11 @@ import clsx from "clsx"; import { useEffect, useRef, useState } from "react"; import { useDevice } from "../components/App"; -import { exportToSvg } from "../packages/utils"; import { LibraryItem } from "../types"; import "./LibraryUnit.scss"; import { CheckboxItem } from "./CheckboxItem"; import { PlusIcon } from "./icons"; -import { COLOR_PALETTE } from "../colors"; +import { useLibraryItemSvg } from "../hooks/useLibraryItemSvg"; export const LibraryUnit = ({ id, @@ -20,38 +19,30 @@ export const LibraryUnit = ({ id: LibraryItem["id"] | /** for pending item */ null; elements?: LibraryItem["elements"]; isPending?: boolean; - onClick: () => void; + onClick: (id: LibraryItem["id"] | null) => void; selected: boolean; onToggle: (id: string, event: React.MouseEvent) => void; onDrag: (id: string, event: React.DragEvent) => void; }) => { const ref = useRef(null); + const svg = useLibraryItemSvg(id, elements); + useEffect(() => { const node = ref.current; + if (!node) { return; } - (async () => { - if (!elements) { - return; - } - const svg = await exportToSvg({ - elements, - appState: { - exportBackground: false, - viewBackgroundColor: COLOR_PALETTE.white, - }, - files: null, - }); + if (svg) { svg.querySelector(".style-fonts")?.remove(); node.innerHTML = svg.outerHTML; - })(); + } return () => { node.innerHTML = ""; }; - }, [elements]); + }, [elements, svg]); const [isHovered, setIsHovered] = useState(false); const isMobile = useDevice().isMobile; @@ -81,7 +72,7 @@ export const LibraryUnit = ({ if (id && event.shiftKey) { onToggle(id, event); } else { - onClick(); + onClick(id); } } : undefined diff --git a/src/components/Spinner.scss b/src/components/Spinner.scss index fd6fd50e8..e2d90f881 100644 --- a/src/components/Spinner.scss +++ b/src/components/Spinner.scss @@ -15,6 +15,7 @@ $duration: 1.6s; svg { animation: rotate $duration linear infinite; + animation-delay: var(--spinner-delay); transform-origin: center center; } diff --git a/src/components/Spinner.tsx b/src/components/Spinner.tsx index c4edb65af..8bc1e5911 100644 --- a/src/components/Spinner.tsx +++ b/src/components/Spinner.tsx @@ -5,13 +5,26 @@ import "./Spinner.scss"; const Spinner = ({ size = "1em", circleWidth = 8, + synchronized = false, }: { size?: string | number; circleWidth?: number; + synchronized?: boolean; }) => { + const mountTime = React.useRef(Date.now()); + const mountDelay = -(mountTime.current % 1600); + return (
- + >( + new Map(), +); + +const exportLibraryItemToSvg = async (elements: LibraryItem["elements"]) => { + return await exportToSvg({ + elements, + appState: { + exportBackground: false, + viewBackgroundColor: COLOR_PALETTE.white, + }, + files: null, + }); +}; + +export const useLibraryItemSvg = ( + id: LibraryItem["id"] | null, + elements: LibraryItem["elements"] | undefined, +): SVGSVGElement | undefined => { + const [svgCache, setSvgCache] = useAtom(libraryItemSvgsCache); + const [svg, setSvg] = useState(); + + useEffect(() => { + if (elements) { + if (id) { + // Try to load cached svg + const cachedSvg = svgCache.get(id); + + if (cachedSvg) { + setSvg(cachedSvg); + } else { + // When there is no svg in cache export it and save to cache + (async () => { + const exportedSvg = await exportLibraryItemToSvg(elements); + + if (exportedSvg) { + setSvgCache(svgCache.set(id, exportedSvg)); + setSvg(exportedSvg); + } + })(); + } + } else { + // When we have no id (usualy selected items from canvas) just export the svg + (async () => { + const exportedSvg = await exportLibraryItemToSvg(elements); + setSvg(exportedSvg); + })(); + } + } + }, [id, elements, svgCache, setSvgCache, setSvg]); + + return svg; +}; From fecbde3f5cff17783e6d7fa355b2f7890d2fcc9f Mon Sep 17 00:00:00 2001 From: Excalidraw Bot <77840495+excalibot@users.noreply.github.com> Date: Wed, 24 May 2023 16:50:11 +0200 Subject: [PATCH 078/451] chore: Update translations from Crowdin (#6598) * New translations en.json (Greek) * New translations en.json (Slovenian) * New translations en.json (Portuguese, Brazilian) * Auto commit: Calculate translation coverage * New translations en.json (German) * Auto commit: Calculate translation coverage * New translations en.json (Korean) * New translations en.json (Chinese Traditional) * Auto commit: Calculate translation coverage * New translations en.json (Norwegian Bokmal) * Auto commit: Calculate translation coverage * New translations en.json (Indonesian) * New translations en.json (Indonesian) * Auto commit: Calculate translation coverage * New translations en.json (Indonesian) * Auto commit: Calculate translation coverage * New translations en.json (Indonesian) * Auto commit: Calculate translation coverage * New translations en.json (Chinese Simplified) * Auto commit: Calculate translation coverage * New translations en.json (Romanian) * Auto commit: Calculate translation coverage * New translations en.json (Romanian) * Auto commit: Calculate translation coverage * New translations en.json (Russian) * Auto commit: Calculate translation coverage * New translations en.json (Slovak) * Auto commit: Calculate translation coverage * New translations en.json (Italian) * Auto commit: Calculate translation coverage * New translations en.json (Italian) * Auto commit: Calculate translation coverage * New translations en.json (Kurdish) * New translations en.json (Swedish) * Auto commit: Calculate translation coverage * New translations en.json (Portuguese) * Auto commit: Calculate translation coverage * New translations en.json (Portuguese) * Auto commit: Calculate translation coverage * New translations en.json (Khmer) * New translations en.json (Khmer) * Auto commit: Calculate translation coverage * New translations en.json (Khmer) * Auto commit: Calculate translation coverage * New translations en.json (Khmer) * Auto commit: Calculate translation coverage * New translations en.json (Khmer) * Auto commit: Calculate translation coverage * New translations en.json (Khmer) * Auto commit: Calculate translation coverage * New translations en.json (Khmer) * New translations en.json (Khmer) * Auto commit: Calculate translation coverage * New translations en.json (Khmer) * Auto commit: Calculate translation coverage * New translations en.json (Khmer) * Auto commit: Calculate translation coverage --- src/locales/de-DE.json | 38 +- src/locales/el-GR.json | 38 +- src/locales/id-ID.json | 58 +-- src/locales/it-IT.json | 40 +- src/locales/km-KH.json | 718 +++++++++++++++++------------------ src/locales/ko-KR.json | 38 +- src/locales/ku-TR.json | 4 +- src/locales/nb-NO.json | 38 +- src/locales/percentages.json | 32 +- src/locales/pt-BR.json | 38 +- src/locales/pt-PT.json | 28 +- src/locales/ro-RO.json | 38 +- src/locales/ru-RU.json | 38 +- src/locales/sk-SK.json | 38 +- src/locales/sl-SI.json | 38 +- src/locales/sv-SE.json | 38 +- src/locales/zh-CN.json | 38 +- src/locales/zh-TW.json | 38 +- 18 files changed, 668 insertions(+), 668 deletions(-) diff --git a/src/locales/de-DE.json b/src/locales/de-DE.json index 8e5518569..44a748c4d 100644 --- a/src/locales/de-DE.json +++ b/src/locales/de-DE.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Transparent", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Schwarz", + "white": "Weiß", + "red": "Rot", + "pink": "Pink", + "grape": "Traube", + "violet": "Violett", + "gray": "Grau", + "blue": "Blau", + "cyan": "Cyan", + "teal": "Blaugrün", + "green": "Grün", + "yellow": "Gelb", + "orange": "Orange", + "bronze": "Bronze" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Beliebteste benutzerdefinierte Farben", + "colors": "Farben", + "shades": "Schattierungen", + "hexCode": "Hex-Code", + "noShades": "Keine Schattierungen für diese Farbe verfügbar" } } diff --git a/src/locales/el-GR.json b/src/locales/el-GR.json index e1008e05c..638254cd0 100644 --- a/src/locales/el-GR.json +++ b/src/locales/el-GR.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Διαφανές", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Μαύρο", + "white": "Λευκό", + "red": "Κόκκινο", + "pink": "Ροζ", + "grape": "Σταφυλί", + "violet": "Βιολετί", + "gray": "Γκρι", + "blue": "Μπλε", + "cyan": "Κυανό", + "teal": "Τιρκουάζ", + "green": "Πράσινο", + "yellow": "Κίτρινο", + "orange": "Πορτοκαλί", + "bronze": "Χαλκινο" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Πιο χρησιμοποιούμενα χρώματα", + "colors": "Χρώματα", + "shades": "Αποχρώσεις", + "hexCode": "Κωδικός Hex", + "noShades": "Δεν υπάρχουν διαθέσιμες αποχρώσεις για αυτό το χρώμα" } } diff --git a/src/locales/id-ID.json b/src/locales/id-ID.json index 37ecf6a18..84abeef73 100644 --- a/src/locales/id-ID.json +++ b/src/locales/id-ID.json @@ -54,7 +54,7 @@ "veryLarge": "Sangat besar", "solid": "Padat", "hachure": "Garis-garis", - "zigzag": "", + "zigzag": "Zigzag", "crossHatch": "Asiran silang", "thin": "Lembut", "bold": "Tebal", @@ -111,7 +111,7 @@ "increaseFontSize": "Besarkan ukuran font", "unbindText": "Lepas teks", "bindText": "Kunci teks ke kontainer", - "createContainerFromText": "", + "createContainerFromText": "Bungkus teks dalam kontainer", "link": { "edit": "Edit tautan", "create": "Buat tautan", @@ -208,10 +208,10 @@ "collabSaveFailed": "Tidak dapat menyimpan ke dalam basis data server. Jika masih berlanjut, Anda sebaiknya simpan berkas Anda secara lokal untuk memastikan pekerjaan Anda tidak hilang.", "collabSaveFailed_sizeExceeded": "Tidak dapat menyimpan ke dalam basis data server, tampaknya ukuran kanvas terlalu besar. Anda sebaiknya simpan berkas Anda secara lokal untuk memastikan pekerjaan Anda tidak hilang.", "brave_measure_text_error": { - "line1": "", - "line2": "", - "line3": "", - "line4": "" + "line1": "Sepertinya Anda menggunkan peramban Brave dengan pengaturan Blokir Fingerprinting yang Agresif diaktifkan.", + "line2": "Ini dapat membuat Elemen Teks dalam gambar mu.", + "line3": "Kami sangat menyarankan mematikan pengaturan ini. Anda dapat mengikuti langkah-langkah ini untuk melakukannya.", + "line4": "Jika mematikan pengaturan ini tidak membenarkan tampilan elemen teks, mohon buka\nisu di GitHub kami, atau chat kami di Discord" } }, "toolBar": { @@ -229,7 +229,7 @@ "penMode": "Mode pena - mencegah sentuhan", "link": "Tambah/Perbarui tautan untuk bentuk yang dipilih", "eraser": "Penghapus", - "hand": "" + "hand": "Tangan (alat panning)" }, "headings": { "canvasActions": "Opsi Kanvas", @@ -237,7 +237,7 @@ "shapes": "Bentuk" }, "hints": { - "canvasPanning": "", + "canvasPanning": "Untuk memindahkan kanvas, tekan roda mouse atau spacebar sambil menyeret, atau menggunakan alat tangan", "linearElement": "Klik untuk memulai banyak poin, seret untuk satu baris", "freeDraw": "Klik dan seret, lepaskan jika Anda selesai", "text": "Tip: Anda juga dapat menambahkan teks dengan klik ganda di mana saja dengan alat pemilihan", @@ -306,8 +306,8 @@ "doubleClick": "klik-ganda", "drag": "seret", "editor": "Editor", - "editLineArrowPoints": "", - "editText": "", + "editLineArrowPoints": "Edit titik garis/panah", + "editText": "Edit teks / tambah label", "github": "Menemukan masalah? Kirimkan", "howto": "Ikuti panduan kami", "or": "atau", @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Transparan", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Hitam", + "white": "Putih", + "red": "Merah", + "pink": "Pink", + "grape": "Ungu", + "violet": "Violet", + "gray": "Abu-abu", + "blue": "Biru", + "cyan": "Cyan", + "teal": "Teal", + "green": "Hijau", + "yellow": "Kuning", + "orange": "Jingga", + "bronze": "Tembaga" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Warna yang sering dipakai", + "colors": "Warna", + "shades": "Nuansa", + "hexCode": "Kode hexa", + "noShades": "Tidak ada nuansa untuk warna ini" } } diff --git a/src/locales/it-IT.json b/src/locales/it-IT.json index d8e8afd5a..775cced8f 100644 --- a/src/locales/it-IT.json +++ b/src/locales/it-IT.json @@ -111,7 +111,7 @@ "increaseFontSize": "Aumenta la dimensione dei caratteri", "unbindText": "Scollega testo", "bindText": "Associa il testo al container", - "createContainerFromText": "", + "createContainerFromText": "Avvolgi il testo in un container", "link": { "edit": "Modifica link", "create": "Crea link", @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Trasparente", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Nero", + "white": "Bianco", + "red": "Rosso", + "pink": "Rosa", + "grape": "Uva", + "violet": "Viola", + "gray": "Grigio", + "blue": "Blu", + "cyan": "Ciano", + "teal": "Verde acqua", + "green": "Verde", + "yellow": "Giallo", + "orange": "Arancio", + "bronze": "Bronzo" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Colori personalizzati più utilizzati", + "colors": "Colori", + "shades": "Sfumature", + "hexCode": "Codice esadecimale", + "noShades": "Nessuna sfumatura disponibile per questo colore" } } diff --git a/src/locales/km-KH.json b/src/locales/km-KH.json index a51c437a2..d49abb45b 100644 --- a/src/locales/km-KH.json +++ b/src/locales/km-KH.json @@ -1,414 +1,414 @@ { "labels": { - "paste": "", - "pasteAsPlaintext": "", - "pasteCharts": "", - "selectAll": "", - "multiSelect": "", - "moveCanvas": "", - "cut": "", - "copy": "", - "copyAsPng": "", - "copyAsSvg": "", - "copyText": "", - "bringForward": "", - "sendToBack": "", - "bringToFront": "", - "sendBackward": "", - "delete": "", - "copyStyles": "", - "pasteStyles": "", - "stroke": "", - "background": "", - "fill": "", - "strokeWidth": "", - "strokeStyle": "", - "strokeStyle_solid": "", - "strokeStyle_dashed": "", - "strokeStyle_dotted": "", - "sloppiness": "", - "opacity": "", - "textAlign": "", - "edges": "", - "sharp": "", - "round": "", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", - "arrowhead_triangle": "", - "fontSize": "", - "fontFamily": "", - "onlySelected": "", - "withBackground": "", - "exportEmbedScene": "", - "exportEmbedScene_details": "", - "addWatermark": "", - "handDrawn": "", - "normal": "", - "code": "", - "small": "", - "medium": "", - "large": "", - "veryLarge": "", - "solid": "", - "hachure": "", - "zigzag": "", - "crossHatch": "", - "thin": "", - "bold": "", - "left": "", - "center": "", - "right": "", - "extraBold": "", - "architect": "", - "artist": "", - "cartoonist": "", - "fileTitle": "", - "colorPicker": "", - "canvasColors": "", - "canvasBackground": "", - "drawingCanvas": "", - "layers": "", - "actions": "", - "language": "", - "liveCollaboration": "", - "duplicateSelection": "", - "untitled": "", - "name": "", - "yourName": "", - "madeWithExcalidraw": "", - "group": "", - "ungroup": "", - "collaborators": "", - "showGrid": "", - "addToLibrary": "", - "removeFromLibrary": "", - "libraryLoadingMessage": "", - "libraries": "", - "loadingScene": "", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "", - "flipHorizontal": "", - "flipVertical": "", - "viewMode": "", - "toggleExportColorScheme": "", - "share": "", - "showStroke": "", - "showBackground": "", - "toggleTheme": "", - "personalLib": "", - "excalidrawLib": "", - "decreaseFontSize": "", - "increaseFontSize": "", - "unbindText": "", - "bindText": "", - "createContainerFromText": "", + "paste": "បិទភ្ជាប់", + "pasteAsPlaintext": "បិទភ្ជាប់ជាអត្ថបទធម្មតា", + "pasteCharts": "បិទភ្ជាប់តារាង", + "selectAll": "ជ្រើសរើស​ទាំងអស់", + "multiSelect": "បន្ថែមធាតុទៅលើការជ្រើសរើស", + "moveCanvas": "ផ្លាស់ទីបាវ", + "cut": "កាត់", + "copy": "ចម្លង", + "copyAsPng": "ចម្លងទៅក្តារតម្បៀតខ្ទាស់ជា​ PNG", + "copyAsSvg": "ចម្លងទៅក្តារតម្បៀតខ្ទាស់ជា​ SVG", + "copyText": "ចម្លងទៅក្តារតម្បៀតខ្ទាស់ជា​អត្ថបទ", + "bringForward": "នាំយកទៅលើ", + "sendToBack": "នាំយកទៅក្រោយបង្អស់", + "bringToFront": "នាំយកទៅលើបង្អស់", + "sendBackward": "នាំយកទៅក្រោយ", + "delete": "លុប", + "copyStyles": "ចម្លងរចនាប័ទ្ម", + "pasteStyles": "បិទភ្ជាប់រចនាប័ទ្ម", + "stroke": "ខ្វាច់", + "background": "ផ្ទៃខាងក្រោយ", + "fill": "បំពេញ", + "strokeWidth": "ទទឹងខ្វាច់", + "strokeStyle": "រចនាប័ទ្មរបស់ខ្វាច់", + "strokeStyle_solid": "តាន់", + "strokeStyle_dashed": "ដាច់ៗ", + "strokeStyle_dotted": "ចំណុចៗ", + "sloppiness": "រចនាប័ទ្មបន្ទាត់", + "opacity": "ភាពច្បាស់", + "textAlign": "តម្រឹមអត្ថបទ", + "edges": "គែម", + "sharp": "មុត", + "round": "រាងមូល", + "arrowheads": "ក្បាលព្រួញ", + "arrowhead_none": "គ្មាន", + "arrowhead_arrow": "ព្រួញ", + "arrowhead_bar": "របារ", + "arrowhead_dot": "ចំណុច", + "arrowhead_triangle": "ត្រីកោណ", + "fontSize": "ទំហំពុម្ពអក្សរ", + "fontFamily": "ក្រុម​ពុម្ពអក្សរ", + "onlySelected": "យកផ្នែកដែលត្រូវបានជ្រើសរើស​ប៉ុណ្ណោះ", + "withBackground": "ផ្ទៃខាងក្រោយ", + "exportEmbedScene": "ស៊ីនដែលត្រូវបានបង្កប់", + "exportEmbedScene_details": "ទិន្នន័យរបស់ស៊ីននឹងត្រូវបានរក្សាទុកទៅក្នុងឯកសារ PNG​ ឬ SVG ដូច្នេះស៊ីនអាចស្ដារឡើងវិញពីឯកសារនេះ ប៉ុន្តែទំហំឯកសារដែលនឹងត្រូវបាននាំចេញនេះនឹងកាន់តែធំ។", + "addWatermark": "បន្ថែមវ៉ាត់ធើម៉ាក \"Made with Excalidraw\"", + "handDrawn": "គូរដោយដៃ", + "normal": "ធម្មតា", + "code": "កូដ", + "small": "តូច", + "medium": "មធ្យម", + "large": "ធំ", + "veryLarge": "ធំខ្លាំង", + "solid": "តាន់", + "hachure": "Hachure", + "zigzag": "Zigzag", + "crossHatch": "បន្ទាត់ឆ្នូតៗ", + "thin": "ស្តើង", + "bold": "ដឹត", + "left": "ខាងឆ្វេង", + "center": "កណ្ដាល", + "right": "នៅខាងស្ដាំ", + "extraBold": "ដិតបន្ថែម", + "architect": "ស្ថាបត្យករ", + "artist": "សិល្បៈករ", + "cartoonist": "អ្នកគំនូរជីវចល", + "fileTitle": "ឈ្មោះ​ឯកសារ", + "colorPicker": "ឧបករណ៍​ជ្រើស​ពណ៌", + "canvasColors": "ប្រើលើបាវ", + "canvasBackground": "ផ្ទៃខាងក្រោយបាវ", + "drawingCanvas": "តំបន់គំនូរ", + "layers": "ស្រទាប់", + "actions": "សកម្មភាព", + "language": "ភាសា", + "liveCollaboration": "សហការគ្នាផ្ទាល់...", + "duplicateSelection": "ចម្លង", + "untitled": "គ្មានឈ្មោះ", + "name": "ឈ្មោះ", + "yourName": "ឈ្មោះ​របស់​អ្នក", + "madeWithExcalidraw": "បង្កើតជាមួយ Excalidraw", + "group": "ការជ្រើសរើសជាក្រុម", + "ungroup": "បំបែកក្រុមការជ្រើសរើសជាក្រុម", + "collaborators": "អ្នកសហការ", + "showGrid": "បង្ហាញក្រឡាចត្រង្គ", + "addToLibrary": "បន្ថែមទៅបណ្ណាល័យ", + "removeFromLibrary": "លុបចេញពីបណ្ណាល័យ", + "libraryLoadingMessage": "កំពុងផ្ទុកបណ្ណាល័យ...", + "libraries": "រកមើលបណ្ណាល័យ", + "loadingScene": "កំពុង​ផ្ទុក​ស៊ីន...", + "align": "តម្រឹម", + "alignTop": "តម្រឹមផ្នែកខាងលើ", + "alignBottom": "តម្រឹមផ្នែកខាងក្រោម", + "alignLeft": "​តម្រឹម​ឆ្វេង", + "alignRight": "តម្រឹម​ស្តាំ", + "centerVertically": "កណ្តាល​បញ្ឈរ", + "centerHorizontally": "កណ្តាល​ផ្ដេក", + "distributeHorizontally": "ចែកចាយផ្ដេក", + "distributeVertically": "ចែកចាយបញ្ឈរ", + "flipHorizontal": "ត្រឡប់​ដោយ​ផ្ដេក", + "flipVertical": "ត្រឡប់​ដោយ​បញ្ឈរ", + "viewMode": "ម៉ូដ​បង្ហាញ", + "toggleExportColorScheme": "បិទ/បើក​ពណ៌​ចម្រុះ​នាំចេញ", + "share": "ចែករំលែក", + "showStroke": "បង្ហាញឧបករណ៍ជ្រើសរើសពណ៌ខ្វាច់", + "showBackground": "បង្ហាញឧបករណ៍ជ្រើសរើសពណ៌ផ្ទៃខាងក្រោយ", + "toggleTheme": "បិទ/បើកប្រធានបទ", + "personalLib": "បណ្ណាល័យផ្ទាល់ខ្លួន", + "excalidrawLib": "បណ្ណាល័យ Excalidraw", + "decreaseFontSize": "បន្ថយទំហំពុម្ពអក្សរ", + "increaseFontSize": "បង្កើនទំហំពុម្ពអក្សរ", + "unbindText": "ស្រាយអត្ថបទ", + "bindText": "ភ្ជាប់អត្ថបទទៅប្រអប់", + "createContainerFromText": "រុំអត្ថបទក្នុងប្រអប់មួយ", "link": { - "edit": "", - "create": "", - "label": "" + "edit": "កែតំណភ្ជាប់", + "create": "បង្កើតតំណភ្ជាប់", + "label": "តំណ" }, "lineEditor": { - "edit": "", - "exit": "" + "edit": "កែសម្រួលបន្ទាត់", + "exit": "ចាកចេញពីការកែសម្រួលបន្ទាត់" }, "elementLock": { - "lock": "", - "unlock": "", - "lockAll": "", - "unlockAll": "" + "lock": "ចាក់សោ", + "unlock": "ដោះសោ", + "lockAll": "ចាក់សោទាំងអស់", + "unlockAll": "ដោះសោទាំងអស់" }, - "statusPublished": "", - "sidebarLock": "" + "statusPublished": "ត្រូវបានបោះពុម្ពផ្សាយ", + "sidebarLock": "ទុករបារចំហៀងបើក" }, "library": { - "noItems": "", - "hint_emptyLibrary": "", - "hint_emptyPrivateLibrary": "" + "noItems": "មិនទាន់មានធាតុបន្ថែមទេ...", + "hint_emptyLibrary": "ជ្រើសរើសធាតុនៅលើបាវដើម្បីបន្ថែមវានៅទីនេះ ឬដំឡើងបណ្ណាល័យពីឃ្លាំងសាធារណៈខាងក្រោម។", + "hint_emptyPrivateLibrary": "ជ្រើសរើសធាតុនៅលើបាវដើម្បីបន្ថែមវានៅទីនេះ" }, "buttons": { - "clearReset": "", - "exportJSON": "", - "exportImage": "", - "export": "", - "exportToPng": "", - "exportToSvg": "", - "copyToClipboard": "", - "copyPngToClipboard": "", - "scale": "", - "save": "", - "saveAs": "", - "load": "", - "getShareableLink": "", - "close": "", - "selectLanguage": "", - "scrollBackToContent": "", - "zoomIn": "", - "zoomOut": "", - "resetZoom": "", - "menu": "", - "done": "", - "edit": "", - "undo": "", - "redo": "", - "resetLibrary": "", - "createNewRoom": "", - "fullScreen": "", - "darkMode": "", - "lightMode": "", - "zenMode": "", - "exitZenMode": "", - "cancel": "", - "clear": "", - "remove": "", - "publishLibrary": "", - "submit": "", - "confirm": "" + "clearReset": "កំណត់បាវឡើងវិញ", + "exportJSON": "នាំចេញជាឯកសារ", + "exportImage": "នាំរូបភាពចេញ", + "export": "រក្សាទុក​នៅ...", + "exportToPng": "នាំចេញជា PNG", + "exportToSvg": "នាំចេញជា SVG", + "copyToClipboard": "ចម្លងទៅក្តារតម្បៀតខ្ទាស់", + "copyPngToClipboard": "ចម្លង PNG ទៅក្តារតម្បៀតខ្ទាស់", + "scale": "មាត្រដ្ឋាន", + "save": "រក្សាទុកទៅឯកសារបច្ចុប្បន្ន", + "saveAs": "រក្សាទុក​ជា", + "load": "បើក", + "getShareableLink": "យកតំណដែលអាចចែករំលែកបាន", + "close": "បិទ", + "selectLanguage": "រើសភាសា", + "scrollBackToContent": "រំកិលត្រឡប់ទៅមាតិកាវិញ", + "zoomIn": "ពង្រីក", + "zoomOut": "បង្រួម", + "resetZoom": "កំណត់ការពង្រីកឡើងវិញ", + "menu": "ម៉ឺនុយ", + "done": "រួចរាល់", + "edit": "កែ", + "undo": "ត្រឡប់វិញ", + "redo": "ធ្វើ​វិញ", + "resetLibrary": "កំណត់បណ្ណាល័យឡើងវិញ", + "createNewRoom": "បង្កើតបន្ទប់ថ្មី", + "fullScreen": "ពេញ​អេក្រង់", + "darkMode": "ម៉ូដងងឹត", + "lightMode": "ម៉ូដភ្លឺ", + "zenMode": "ម៉ូត Zen", + "exitZenMode": "ចេញពី zen​ ម៉ូត", + "cancel": "បោះបង់", + "clear": "សម្អាត", + "remove": "ដកចេញ", + "publishLibrary": "បោះពុម្ពផ្សាយ", + "submit": "ដាក់​ស្នើ", + "confirm": "បញ្ជាក់" }, "alerts": { - "clearReset": "", - "couldNotCreateShareableLink": "", - "couldNotCreateShareableLinkTooBig": "", - "couldNotLoadInvalidFile": "", - "importBackendFailed": "", - "cannotExportEmptyCanvas": "", - "couldNotCopyToClipboard": "", - "decryptFailed": "", - "uploadedSecurly": "", - "loadSceneOverridePrompt": "", - "collabStopOverridePrompt": "", - "errorAddingToLibrary": "", - "errorRemovingFromLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "", - "invalidSceneUrl": "", - "resetLibrary": "", - "removeItemsFromsLibrary": "", - "invalidEncryptionKey": "", - "collabOfflineWarning": "" + "clearReset": "វានឹងសម្អាតបាវទាំងមូល។ តើ​អ្នក​ប្រាកដ​ឬ​អត់?", + "couldNotCreateShareableLink": "មិនអាចបង្កើតតំណដែលអាចចែករំលែកបានទេ។", + "couldNotCreateShareableLinkTooBig": "មិន​អាច​បង្កើត​តំណ​ដែល​អាច​ចែក​រំលែក​បាន៖ ស៊ីន​ធំ​ពេក", + "couldNotLoadInvalidFile": "មិនអាចផ្ទុកឯកសារមិនត្រឹមត្រូវបានទេ។", + "importBackendFailed": "ការនាំចូលពីម៉ាស៊ីនមេបានបរាជ័យ។", + "cannotExportEmptyCanvas": "មិនអាចនាំចេញបាវទទេបានទេ។", + "couldNotCopyToClipboard": "មិនអាចចម្លងទៅក្ដារតម្បៀតខ្ទាស់បានទេ។", + "decryptFailed": "មិនអាចឌិគ្រីបទិន្នន័យបានទេ។", + "uploadedSecurly": "ការបង្ហោះត្រូវបានការពារដោយការអ៊ិនគ្រីបពីចុងដល់ចប់ មានន័យថា ទាំងម៉ាស៊ីនមេរបស់ Excalidraw ឬភាគីទីបីមិនអាចអានខ្លឹមសារបានទេ។", + "loadSceneOverridePrompt": "ការផ្ទុកគំនូរខាងក្រៅនឹងជំនួសមាតិកាដែលមានស្រាប់របស់អ្នក។ តើអ្នកចង់បន្តទេ?", + "collabStopOverridePrompt": "ការបញ្ឈប់សម័យនឹងសរសេរជាន់លើគំនូរដែលបានរក្សាទុកនៅលើកុំព្យូទ័ររបស់អ្នកពីមុន។ តើ​អ្នក​ប្រាកដ​ឬ​អត់?\n\n(ប្រសិនបើអ្នកចង់រក្សាគំនូរដែលនៅលើកុំព្យូទ័ររបស់អ្នក គ្រាន់តែបិទផ្ទាំងកម្មវិធីរុករក។)", + "errorAddingToLibrary": "មិនអាចបន្ថែមធាតុទៅបណ្ណាល័យបានទេ", + "errorRemovingFromLibrary": "មិនអាចលុបធាតុចេញពីបណ្ណាល័យបានទេ", + "confirmAddLibrary": "វានឹងបន្ថែមរូបរាង {{numShapes}} ទៅបណ្ណាល័យរបស់អ្នក។ តើ​អ្នក​ប្រាកដ​ឬ​អត់?", + "imageDoesNotContainScene": "រូបភាពនេះហាក់ដូចជាមិនមានទិន្នន័យស៊ីនណាមួយទេ។ តើអ្នកបានបើកការបង្កប់ស៊ីននៅពេលនាំចេញទេ?", + "cannotRestoreFromImage": "មិនអាចស្ដារស៊ីនពីឯកសាររូបភាពនេះបានទេ", + "invalidSceneUrl": "មិន​អាច​នាំចូល​ស៊ីន​ពី URL ដែល​បាន​ផ្តល់​ឱ្យ​ទេ។ វាមានទម្រង់ខុស ឬមិនមានទិន្នន័យ Excalidraw JSON ដែលត្រឹមត្រូវ។", + "resetLibrary": "វានឹងសម្អាតបាវទាំងមូល។ តើ​អ្នក​ប្រាកដ​ឬ​អត់?", + "removeItemsFromsLibrary": "តើអ្នកប្រាកដថាចង់លុប {{count}} ធាតុចេញពីបណ្ណាល័យទេ?", + "invalidEncryptionKey": "សោអ៊ីនគ្រីបត្រូវតែមាន 22 តួអក្សរ។ ការសហការផ្ទាល់ត្រូវបានបិទ។", + "collabOfflineWarning": "គ្មានការតភ្ជាប់អ៊ីនធឺណិត។\nការផ្លាស់ប្តូររបស់អ្នកនឹងមិនត្រូវបានរក្សាទុកទេ!" }, "errors": { - "unsupportedFileType": "", - "imageInsertError": "", - "fileTooBig": "", - "svgImageInsertError": "", - "invalidSVGString": "", - "cannotResolveCollabServer": "", - "importLibraryError": "", - "collabSaveFailed": "", - "collabSaveFailed_sizeExceeded": "", + "unsupportedFileType": "ប្រភេទឯកសារមិនត្រូវបានគាំទ្រទេ។", + "imageInsertError": "មិនអាចបញ្ចូលរូបភាពបានទេ។ សូម​ព្យាយាម​ម្តង​ទៀត​នៅ​ពេល​ក្រោយ……", + "fileTooBig": "ឯកសារធំពេក។ ទំហំអតិបរមាដែលអនុញ្ញាតគឺ {{maxSize}}។", + "svgImageInsertError": "មិនអាចបញ្ចូលរូបភាព SVG បានទេ។ ស្លាក SVG ហាក់ដូចជាមិនត្រឹមត្រូវ។", + "invalidSVGString": "SVG មិន​ត្រឹមត្រូវ។", + "cannotResolveCollabServer": "មិនអាចភ្ជាប់ទៅម៉ាស៊ីនមេសហការផ្ទាល់បានទេ។ សូមផ្ទុកទំព័រឡើងវិញ ហើយព្យាយាមម្តងទៀត។", + "importLibraryError": "មិនអាចផ្ទុកបណ្ណាល័យបានទេ។", + "collabSaveFailed": "មិនអាចរក្សាទុកទៅម៉ាស៊ីនមេបានទេ។ ប្រសិនបើបញ្ហានៅតែបន្តកើតមាន​ អ្នកគួរតែរក្សាទុកឯកសាររបស់អ្នកនៅលើកុំព្យូទ័ររបស់អ្នកសិន ដើម្បីធានាថាការងាររបស់អ្នកមិនបាត់បង់។", + "collabSaveFailed_sizeExceeded": "មិនអាចរក្សាទុកទៅម៉ាស៊ីនមេបានទេ, ផ្ទាំងបាវហាក់ដូចជាធំពេក។ អ្នកគួរតែរក្សាទុកឯកសាររបស់អ្នកនៅលើកុំព្យូទ័ររបស់អ្នកសិន ដើម្បីធានាថាការងាររបស់អ្នកមិនបាត់បង់។", "brave_measure_text_error": { - "line1": "", - "line2": "", - "line3": "", - "line4": "" + "line1": "អ្នកហាក់ដូចជាកំពុងប្រើប្រាស់កម្មវិធីរុករកតាមអ៊ីនធឺណិត Brave ជាមួយនឹងការកំណត់ ការពារស្នាមម្រាមដៃយ៉ាងធ្ងន់ធ្ងរ ត្រូវបានបើក។", + "line2": "វាអាចបណ្តាលឱ្យមានការបំបែក ធាតុអត្ថបទ នៅក្នុងគំនូររបស់អ្នក។", + "line3": "យើងណែនាំយ៉ាងមុតមាំឱ្យបិទការកំណត់នេះ។ អ្នកអាចអនុវត្តតាម ជំហានទាំងនេះ ដើម្បីបិទការកំណត់នេះ។", + "line4": "ប្រសិនបើការបិទការកំណត់នេះមិនបានជួសជុលការបង្ហាញធាតុអត្ថបទទេ សូមដាក់ issue នៅលើ GitHub ឬរាយការណ៍នៅលើ Discord របស់យើង" } }, "toolBar": { - "selection": "", - "image": "", - "rectangle": "", - "diamond": "", - "ellipse": "", - "arrow": "", - "line": "", - "freedraw": "", - "text": "", - "library": "", - "lock": "", - "penMode": "", - "link": "", - "eraser": "", - "hand": "" + "selection": "ការជ្រើសរើស", + "image": "បញ្ចូលរូបភាព", + "rectangle": "ចតុ​កោណ​កែង​", + "diamond": "ពេជ្រ", + "ellipse": "ពងក្រពើ", + "arrow": "ព្រួញ", + "line": "បន្ទាត់", + "freedraw": "គូរ", + "text": "អត្ថបទ", + "library": "បណ្ណាល័យ", + "lock": "រក្សារឧបករណ៍ដែលបានជ្រើសរើសបន្ទាប់ពីគូររួច", + "penMode": "របៀបប៊ិច - ជៀសវាងការប៉ះ", + "link": "បន្ថែម/ធ្វើបច្ចុប្បន្នភាពតំណភ្ជាប់សម្រាប់រូបរាងដែលបានជ្រើសរើស", + "eraser": "ជ័រលុប", + "hand": "ដៃ (panning tool)" }, "headings": { - "canvasActions": "", - "selectedShapeActions": "", - "shapes": "" + "canvasActions": "សកម្មភាពបាវ", + "selectedShapeActions": "សកម្មភាពរបស់រាងដែលបានជ្រើសរើស", + "shapes": "រាង" }, "hints": { - "canvasPanning": "", - "linearElement": "", - "freeDraw": "", - "text": "", - "text_selected": "", - "text_editing": "", - "linearElementMulti": "", - "lockAngle": "", - "resize": "", - "resizeImage": "", - "rotate": "", - "lineEditor_info": "", - "lineEditor_pointSelected": "", - "lineEditor_nothingSelected": "", - "placeImage": "", - "publishLibrary": "", - "bindTextToElement": "", - "deepBoxSelect": "", - "eraserRevert": "", - "firefox_clipboard_write": "" + "canvasPanning": "ដើម្បីផ្លាស់ទីបាវ សូមសង្កត់កង់កណ្ដុរឬគ្រាប់ចុចspacebarខណៈពេលកំពុងអូស ឬប្រើឧបករណ៍ដៃ។", + "linearElement": "ចុចដើម្បីបង្កើតចំណុចច្រើន អូសដើម្បីបង្កើតបន្ទាត់មួយ", + "freeDraw": "ចុច​ហើយ​អូស លែង​ពេល​រួចរាល់", + "text": "គន្លឹះ៖ អ្នកក៏អាចបន្ថែមអត្ថបទដោយចុចពីរដងនៅកន្លែងណាមួយដោយប្រើឧបករណ៍ជ្រើសរើស", + "text_selected": "ចុចពីរដង ឬចុច ENTER ដើម្បីកែសម្រួលអត្ថបទ", + "text_editing": "ចុច Escape ឬ CtrlOrCmd +ENTER ដើម្បីបញ្ចប់ការកែសម្រួល", + "linearElementMulti": "ចុចលើចំណុចចុងក្រោយ ឬចុច Esc/Enter ដើម្បីបញ្ចប់", + "lockAngle": "អ្នកអាចសង្កត់ Shift ដើម្បីកំណត់មុំ", + "resize": "អ្នកអាចសង្កត់ SHIFT ដើម្បីបងំ្ខឲមានសមាមាត្រ ខណៈពេលដែលប្តូរទំហំ\nសង្កត់ ALT ដើម្បីប្តូរទំហំពីកណ្តាល", + "resizeImage": "អ្នកអាចប្តូរទំហំរូបភាពដោយសេរីដោយសង្កត់ SHIFT,\nសង្កត់ ALT ដើម្បីប្តូរទំហំពីកណ្តាល", + "rotate": "អ្នកអាចសង្កត់ Shift ខណៈពេលកំពុងបង្វិល ដើម្បីកម្រិតមុំ", + "lineEditor_info": "សង្កត់ CtrlOrCmd ហើយចុចពីរដង ឬចុច CtrlOrCmd + Enter ដើម្បីកែសម្រួលចំណុច", + "lineEditor_pointSelected": "ចុច Delete ដើម្បីលុបចំណុច(ច្រើន)\nCtrlOrCmd+D ដើម្បីចម្លង, ឬអូសដើម្បីផ្លាស់ទី", + "lineEditor_nothingSelected": "ជ្រើសរើសចំណុចដែលត្រូវកែសម្រួល (សង្កត់ SHIFT ដើម្បីជ្រើសរើសច្រើនចំណុច)\nឬ សង្កត់ Alt ហើយចុចដើម្បីបន្ថែមចំណុចថ្មី។", + "placeImage": "ចុចដើម្បីដាក់រូបភាព ឬចុចហើយអូសដើម្បីកំណត់ទំហំរបស់រូបភាពដោយដៃ", + "publishLibrary": "បោះពុម្ពផ្សាយបណ្ណាល័យផ្ទាល់ខ្លួនរបស់អ្នក", + "bindTextToElement": "ចុច Enter ដើម្បីបន្ថែមអត្ថបទ", + "deepBoxSelect": "សង្កត់ CtrlOrCmd ដើម្បីជ្រើសរើសយ៉ាងជ្រៅ និងជៀសវាងការអូស", + "eraserRevert": "សង្កត់ Alt ដើម្បីដកការជ្រើសរើសធាតុដែលត្រូវបានសម្គាល់សម្រាប់ការលុប", + "firefox_clipboard_write": "បើកមុខងារនេះដោយកំណត់ទង់ \"dom.events.asyncClipboard.clipboardItem\" ទៅ \"true\" \nដើម្បីផ្លាស់ប្តូរទង់កម្មវិធីរុករកនៅក្នុង Firefox សូមចូលទៅកាន់ទំព័រ \"about:config\"។" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "មិនអាចបង្ហាញការមើលជាមុនបាន", + "canvasTooBig": "បាវអាចមានទំហំធំពេក។", + "canvasTooBigTip": "គន្លឹះ៖ ព្យាយាមផ្លាស់ទីធាតុដែលឆ្ងាយបំផុតឱ្យទៅជិតគ្នាបន្តិច។" }, "errorSplash": { - "headingMain": "", - "clearCanvasMessage": "", - "clearCanvasCaveat": "", - "trackedToSentry": "", - "openIssueMessage": "", - "sceneContent": "" + "headingMain": "បានជួបប្រទះកំហុសមួយ។ សូមព្យាយាម ។", + "clearCanvasMessage": "ប្រសិនបើការផ្ទុកឡើងវិញមិនអាចដោះស្រាយកំហុសបានទេ សូមសាកល្បង ", + "clearCanvasCaveat": " នេះនឹងបណ្តាលឱ្យបាត់បង់ការងារ ", + "trackedToSentry": "កំហុសជាមួយលេខសម្គាល់ {{eventId}} ត្រូវបានតាមដាននៅលើប្រព័ន្ធរបស់យើង។", + "openIssueMessage": "យើងមានការប្រុងប្រយ័ត្នខ្លាំងណាស់ក្នុងការមិនបញ្ចូលព័ត៌មានរបស់ស៊ីនរបស់អ្នកទៅលើកំហុស។ ប្រសិនបើស៊ីនរបស់អ្នកមិនមានលក្ខណៈឯកជនទេ សូមពិចារណាបន្តទៅកាន់ សូមបញ្ចូលព័ត៌មានខាងក្រោមដោយចម្លង និងបិទភ្ជាប់វាទៅក្នុងបញ្ហារបស់ GitHub។", + "sceneContent": "មាតិកាបាវ៖" }, "roomDialog": { - "desc_intro": "", - "desc_privacy": "", - "button_startSession": "", - "button_stopSession": "", - "desc_inProgressIntro": "", - "desc_shareLink": "", - "desc_exitSession": "", - "shareTitle": "" + "desc_intro": "អ្នកអាចអញ្ជើញអ្នកដទៃឱ្យសហការជាមួយអ្នកនៅលើស៊ីនបច្ចុប្បន្ន។", + "desc_privacy": "កុំបារម្ភ វគ្គប្រើការអ៊ិនគ្រីបពីចុងដល់ចប់ ដូច្នេះអ្វីដែលអ្នកគូរនឹងនៅតែជាឯកជន។ សូម្បីតែម៉ាស៊ីនមេរបស់យើងក៏នឹងមិនអាចមើលឃើញអ្វីដែលអ្នកកំពុងធ្វើដែរ។", + "button_startSession": "ចាប់ផ្តើមវគ្គ", + "button_stopSession": "បញ្ឈប់វគ្គ", + "desc_inProgressIntro": "វគ្គសហការផ្ទាល់ឥឡូវនេះកំពុងដំណើរការ។", + "desc_shareLink": "ចែករំលែកតំណនេះជាមួយអ្នកដែលអ្នកចង់សហការជាមួយ៖", + "desc_exitSession": "ការបញ្ឈប់វគ្គនេះនឹងផ្តាច់អ្នកចេញពីបន្ទប់ ប៉ុន្តែអ្នកនឹងនៅតែអាចបន្តប្រើបាវនៅលើកុំព្យូទ័ររបស់អ្នក។ សូមចំណាំថាវានឹងមិនប៉ះពាល់ដល់អ្នកប្រើប្រាស់ផ្សេងទៀតទេ​ ហើយពួកគេនឹងនៅតែអាចបន្តសហការលើកំណែរបស់ពួកគេ។", + "shareTitle": "ចូលរួមវគ្គសហការផ្ទាល់នៅលើ Excalidraw" }, "errorDialog": { - "title": "" + "title": "មានកំហុស" }, "exportDialog": { - "disk_title": "", - "disk_details": "", - "disk_button": "", - "link_title": "", - "link_details": "", - "link_button": "", - "excalidrawplus_description": "", - "excalidrawplus_button": "", - "excalidrawplus_exportError": "" + "disk_title": "រក្សាទុកទៅថាស", + "disk_details": "នាំចេញទិន្នន័យរបស់ស៊ីនជាឯកសារដែលអ្នកអាចនាំចូលនៅពេលក្រោយ។", + "disk_button": "រក្សាទុកក្នុងឯកសារ", + "link_title": "តំណដែលអាចចែករំលែកបាន", + "link_details": "នាំចេញជាតំណបានតែមើលឬអាន។", + "link_button": "នាំចេញជាតំណ", + "excalidrawplus_description": "រក្សាទុកស៊ីនទៅកន្លែងធ្វើការ Excalidraw+ របស់អ្នក។", + "excalidrawplus_button": "នាំចេញ", + "excalidrawplus_exportError": "មិនអាចនាំចេញទៅ Excalidraw+ បានទេនៅពេលនេះ..." }, "helpDialog": { - "blog": "", - "click": "", - "deepSelect": "", - "deepBoxSelect": "", - "curvedArrow": "", - "curvedLine": "", - "documentation": "", - "doubleClick": "", - "drag": "", - "editor": "", - "editLineArrowPoints": "", - "editText": "", - "github": "", - "howto": "", - "or": "", - "preventBinding": "", - "tools": "", - "shortcuts": "", - "textFinish": "", - "textNewLine": "", - "title": "", - "view": "", - "zoomToFit": "", - "zoomToSelection": "", - "toggleElementLock": "", - "movePageUpDown": "", - "movePageLeftRight": "" + "blog": "អានប្លក់របស់យើង", + "click": "ចុច", + "deepSelect": "ការជ្រើសរើសជាក្រុម", + "deepBoxSelect": "ជ្រើសរើសជាក្រុម និង ជៀសវាងការអូសទាញផ្លាស់ទី", + "curvedArrow": "ព្រួញកោង", + "curvedLine": "ព្រួញកោង", + "documentation": "ឯកសារ", + "doubleClick": "ចុច​ពីរ​ដង", + "drag": "អូស", + "editor": "កម្មវិធីនិពន្ធ", + "editLineArrowPoints": "កែសម្រួលចំណុចនៃបន្ទាត់ ឬព្រួញ", + "editText": "បន្ថែម ឬកែសម្រួលអត្ថបទ", + "github": "រកឃើញបញ្ហា? ដាក់ស្នើ", + "howto": "ឯកសារជំនួយ", + "or": "ឬ", + "preventBinding": "ទប់ស្កាត់ការចងព្រួញ", + "tools": "ឧបករណ៍", + "shortcuts": "ផ្លូវកាត់ក្តារចុច", + "textFinish": "បញ្ចប់ការកែសម្រួល (កម្មវិធីនិពន្ធអត្ថបទ)", + "textNewLine": "ចុះបន្ទាត់ (កម្មវិធីនិពន្ធអត្ថបទ)", + "title": "ជំនួយ", + "view": "បង្ហាញ", + "zoomToFit": "ធ្វើមាត្រដ្ឋានឱ្យសមនឹងធាតុទាំងអស់។", + "zoomToSelection": "ពង្រីកទៅការជ្រើសរើស", + "toggleElementLock": "ចាក់សោ/ដោះសោការជ្រើសរើស", + "movePageUpDown": "ផ្លាស់ទីទំព័រឡើងលើ/ចុះក្រោម", + "movePageLeftRight": "ផ្លាស់ទីទំព័រទៅឆ្វេង/ស្ដាំ" }, "clearCanvasDialog": { - "title": "" + "title": "សម្អាតបាវ" }, "publishDialog": { - "title": "", - "itemName": "", - "authorName": "", - "githubUsername": "", - "twitterUsername": "", - "libraryName": "", - "libraryDesc": "", - "website": "", + "title": "បោះពុម្ពបណ្ណាល័យ", + "itemName": "ឈ្មោះ​ធាតុ", + "authorName": "ឈ្មោះអ្នកនិពន្ធ", + "githubUsername": "ឈ្មោះអ្នកប្រើ GitHub", + "twitterUsername": "ឈ្មោះអ្នកប្រើ Twitter", + "libraryName": "ឈ្មោះបណ្ណាល័យ", + "libraryDesc": "ការពិពណ៌នាអំពីបណ្ណាល័យ", + "website": "គេហទំព័រ", "placeholder": { - "authorName": "", - "libraryName": "", - "libraryDesc": "", - "githubHandle": "", - "twitterHandle": "", - "website": "" + "authorName": "ឈ្មោះរបស់អ្នក ឬឈ្មោះអ្នកប្រើប្រាស់", + "libraryName": "ឈ្មោះបណ្ណាល័យរបស់អ្នក", + "libraryDesc": "ការពិពណ៌នាអំពីបណ្ណាល័យរបស់អ្នក នឹងអនុញ្ញាតឱ្យអ្នក​ផ្សេងយល់ពីការប្រើប្រាស់របស់វា។", + "githubHandle": "ឈ្មោះអ្នកប្រើ GitHub (ជាជម្រើស) ដូច្នេះអ្នកអាចកែសម្រួលបណ្ណាល័យបាននៅពេលដាក់ស្នើសម្រាប់ការពិនិត្យ", + "twitterHandle": "ឈ្មោះអ្នកប្រើប្រាស់ Twitter (ជាជម្រើស) ដូច្នេះយើងដឹងថាអ្នកណាដែលត្រូវផ្តល់ក្រេឌីតនៅពេលផ្សព្វផ្សាយតាម Twitter", + "website": "ភ្ជាប់ទៅគេហទំព័រផ្ទាល់ខ្លួនរបស់អ្នក ឬគេហទំព័រផ្សេងទៀត (ជាជម្រើស)" }, "errors": { - "required": "", - "website": "" + "required": "ត្រូវបានទាមទារ", + "website": "សូមវាយបញ្ចូល URL ​ដែលត្រឹមត្រូវ" }, - "noteDescription": "", - "noteGuidelines": "", - "noteLicense": "", - "noteItems": "", - "atleastOneLibItem": "", - "republishWarning": "" + "noteDescription": "ដាក់ស្នើបណ្ណាល័យរបស់អ្នកដើម្បីដាក់បញ្ចូលក្នុង ឃ្លាំងបណ្ណាល័យសាធារណៈ សម្រាប់ឲ្យអ្នកផ្សេងប្រើក្នុងគំនូររបស់ពួកគេ។", + "noteGuidelines": "បណ្ណាល័យត្រូវតែអនុម័តដោយដៃជាមុនសិន។ សូមអាន ការណែនាំ មុនពេលដាក់ស្នើ។ ការប្រាស្រ័យទាក់ទងជាបន្តបន្ទាប់ និងការផ្លាស់ប្តូរបណ្ណាល័យទាមទារឱ្យអ្នកមានគណនី GitHub ប៉ុន្តែមិនត្រូវបានទាមទារយ៉ាងតឹងរ៉ឹងទេ។", + "noteLicense": "តាមរយៈការដាក់ស្នើ អ្នកយល់ព្រមថាបណ្ណាល័យនឹងត្រូវបានបោះពុម្ពផ្សាយក្រោម អាជ្ញាប័ណ្ណ MIT ដែលមានន័យយ៉ាងខ្លី អ្នកណាក៏អាចប្រើប្រាស់វាបានដោយគ្មានការរឹតត្បិត។", + "noteItems": "ធាតុនីមួយៗនៅក្នុងបណ្ណាល័យត្រូវតែមានឈ្មោះផ្ទាល់ខ្លួនដើម្បីយើងអាចត្រងវាបាន។ ធាតុខាងក្រោមនឹងត្រូវបានរួមបញ្ចូល:", + "atleastOneLibItem": "សូមជ្រើសរើសយ៉ាងហោចណាស់ធាតុបណ្ណាល័យមួយដើម្បីចាប់ផ្តើម", + "republishWarning": "ចំណាំ៖ ធាតុដែលត្រូវបានជ្រើសរើសមួយចំនួនត្រូវបានសម្គាល់ថាបានបោះពុម្ព/បញ្ជូនរួចរាល់ហើយ។ អ្នកគួរតែបញ្ជូនធាតុឡើងវិញនៅពេលដែលធ្វើបច្ចុប្បន្នភាពបណ្ណាល័យដែលមានស្រាប់ ឬការបញ្ជូន។" }, "publishSuccessDialog": { - "title": "", - "content": "" + "title": "បណ្ណាល័យត្រូវបានដាក់ស្នើ", + "content": "សូមអរគុណ {{authorName}}។ បណ្ណាល័យរបស់អ្នកត្រូវបានបញ្ជូនមកពិនិត្យ។ សូមចុច ទីនេះ ដើម្បីតាមដានស្ថានភាពនៃការដាក់ស្នើនេះ។" }, "confirmDialog": { - "resetLibrary": "", - "removeItemsFromLib": "" + "resetLibrary": "កំណត់បណ្ណាល័យឡើងវិញ", + "removeItemsFromLib": "លុបធាតុដែលបានជ្រើសរើសចេញពីបណ្ណាល័យ" }, "encrypted": { - "tooltip": "", - "link": "" + "tooltip": "គំនូររបស់អ្នកត្រូវបានអ៊ិនគ្រីបពីចុងដល់ចប់ ដូច្នេះម៉ាស៊ីនមេរបស់ Excalidraw នឹងមិនឃើញពួកវាទេ។", + "link": "ប្លក់ផុសលើការអ៊ិនគ្រីបពីចុងដល់ចុងក្នុង Excalidraw" }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "version": "", - "versionCopy": "", - "versionNotAvailable": "", - "width": "" + "angle": "មុំ", + "element": "ធាតុ", + "elements": "ធាតុច្រើន", + "height": "កម្ពស់", + "scene": "ស៊ីន", + "selected": "បានជ្រើសរើស", + "storage": "ការផ្ទុក", + "title": "ស្ថិតិសម្រាប់ nerds", + "total": "សរុប", + "version": "ជំនាន់:", + "versionCopy": "ចុចដើម្បីចម្លង", + "versionNotAvailable": "កំណែមិនអាចប្រើបាន", + "width": "ទទឹង​" }, "toast": { - "addedToLibrary": "", - "copyStyles": "", - "copyToClipboard": "", - "copyToClipboardAsPng": "", - "fileSaved": "", - "fileSavedToFilename": "", - "canvas": "", - "selection": "", - "pasteAsSingleElement": "" + "addedToLibrary": "បានបន្ថែមទៅបណ្ណាល័យ", + "copyStyles": "រចនាប័ទ្មត្រូវបានចម្លង។", + "copyToClipboard": "បានចម្លងទៅក្ដារតម្បៀតខ្ទាស់។", + "copyToClipboardAsPng": "បានចម្លង {{exportSelection}} ទៅក្ដារតម្បៀតខ្ទាស់ជា PNG\n({{exportColorScheme}})", + "fileSaved": "ឯកសារត្រូវបានរក្សាទុក។", + "fileSavedToFilename": "បានរក្សាទុកនៅក្នុង {filename}", + "canvas": "តំបន់គំនូរ", + "selection": "ការជ្រើសរើស", + "pasteAsSingleElement": "ប្រើ {{shortcut}} ដើម្បីបិទភ្ជាប់ជាធាតុតែមួយ,\nឬបិទភ្ជាប់ទៅក្នុងកម្មវិធីនិពន្ធអត្ថបទដែលមានស្រាប់" }, "colors": { "transparent": "ថ្លាមើលធ្លុះ", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "ពណ៍ខ្មៅ", + "white": "ពណ៌ស", + "red": "ពណ៌ក្រហម", + "pink": "ពណ៌ផ្កាឈូក", + "grape": "ពណ៌ទំពាំងបាយជូរ", + "violet": "ពណ៌ស្វាយ", + "gray": "ពណ៌ប្រផេះ", + "blue": "ពណ៌ខៀវ", + "cyan": "ពណ៌ផ្ទៃមេឃ", + "teal": "ពណ៌​ខៀវបៃតង", + "green": "ពណ៌បៃតង", + "yellow": "ពណ៌លឿង", + "orange": "ពណ៌ទឹកក្រូច", + "bronze": "ពណ៌សំរិទ្ធ" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "ពណ៌ផ្ទាល់ខ្លួនដែលប្រើច្រើនបំផុត", + "colors": "ពណ៌", + "shades": "ស្រមោល", + "hexCode": "លេខកូដ hex", + "noShades": "មិនមានស្រមោលសម្រាប់ពណ៌នេះទេ" } } diff --git a/src/locales/ko-KR.json b/src/locales/ko-KR.json index 3ec5233d7..2bb2bc7fa 100644 --- a/src/locales/ko-KR.json +++ b/src/locales/ko-KR.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "투명", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "검정색", + "white": "흰색", + "red": "빨강색", + "pink": "핑크색", + "grape": "그레이프", + "violet": "바이올렛", + "gray": "회색", + "blue": "파란색", + "cyan": "시안", + "teal": "틸", + "green": "녹색", + "yellow": "노란색", + "orange": "주황색", + "bronze": "브론즈" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "자주 사용된 커스텀 색상들", + "colors": "색상", + "shades": "색조", + "hexCode": "Hex 코드", + "noShades": "이 색상에는 색조가 없습니다" } } diff --git a/src/locales/ku-TR.json b/src/locales/ku-TR.json index 90f4ceec6..4ef15d853 100644 --- a/src/locales/ku-TR.json +++ b/src/locales/ku-TR.json @@ -75,10 +75,10 @@ "language": "زمان", "liveCollaboration": "هاوکاریکردنی زیندو...", "duplicateSelection": "لەبەرگرتنەوە", - "untitled": "Untitled", + "untitled": "بێ-ناو", "name": "ناو", "yourName": "ناوەکەت", - "madeWithExcalidraw": "Made with Excalidraw", + "madeWithExcalidraw": "دروستکراوە بە Excalidraw", "group": "دیاریکردنی گروپ", "ungroup": "گروپی دیاریکراوەکان لابەرە", "collaborators": "هاوکارەکان", diff --git a/src/locales/nb-NO.json b/src/locales/nb-NO.json index c624ac8e5..5211a703b 100644 --- a/src/locales/nb-NO.json +++ b/src/locales/nb-NO.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Gjennomsiktig", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Svart", + "white": "Hvit", + "red": "Rød", + "pink": "Rosa", + "grape": "Drue", + "violet": "Fiolett", + "gray": "Grå", + "blue": "Blå", + "cyan": "Turkis", + "teal": "Blågrønn", + "green": "Grønn", + "yellow": "Gul", + "orange": "Oransje", + "bronze": "Bronse" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Mest brukte egendefinerte farger", + "colors": "Farger", + "shades": "Toner", + "hexCode": "Heksadesimal kode", + "noShades": "Ingen toner tilgjengelig for denne fargen" } } diff --git a/src/locales/percentages.json b/src/locales/percentages.json index 1619ae971..09e8386ad 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -5,8 +5,8 @@ "ca-ES": 92, "cs-CZ": 67, "da-DK": 35, - "de-DE": 94, - "el-GR": 92, + "de-DE": 100, + "el-GR": 97, "en": 100, "es-ES": 93, "eu-ES": 94, @@ -17,39 +17,39 @@ "he-IL": 91, "hi-IN": 74, "hu-HU": 80, - "id-ID": 92, - "it-IT": 94, + "id-ID": 100, + "it-IT": 100, "ja-JP": 92, "kaa": 18, "kab-KAB": 92, "kk-KZ": 22, - "km-KH": 2, - "ko-KR": 94, + "km-KH": 100, + "ko-KR": 100, "ku-TR": 94, "lt-LT": 59, "lv-LV": 93, "mr-IN": 93, "my-MM": 43, - "nb-NO": 94, + "nb-NO": 100, "nl-NL": 87, "nn-NO": 81, "oc-FR": 91, "pa-IN": 82, "pl-PL": 83, - "pt-BR": 94, - "pt-PT": 93, - "ro-RO": 94, - "ru-RU": 94, + "pt-BR": 100, + "pt-PT": 97, + "ro-RO": 100, + "ru-RU": 100, "si-LK": 9, - "sk-SK": 94, - "sl-SI": 94, - "sv-SE": 94, + "sk-SK": 100, + "sl-SI": 100, + "sv-SE": 100, "ta-IN": 86, "th-TH": 41, "tr-TR": 91, "uk-UA": 94, "vi-VN": 59, - "zh-CN": 94, + "zh-CN": 100, "zh-HK": 27, - "zh-TW": 94 + "zh-TW": 100 } diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index 30ae031d5..614c782fd 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Transparente", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Preto", + "white": "Branco", + "red": "Vermelho", + "pink": "Rosa", + "grape": "Uva", + "violet": "Violeta", + "gray": "Cinza", + "blue": "Azul", + "cyan": "Ciano", + "teal": "Verde-azulado", + "green": "Verde", + "yellow": "Amarelo", + "orange": "Laranja", + "bronze": "Bronze" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Cores personalizadas mais usadas", + "colors": "Cores", + "shades": "Tons", + "hexCode": "Código hexadecimal", + "noShades": "Sem tons disponíveis para essa cor" } } diff --git a/src/locales/pt-PT.json b/src/locales/pt-PT.json index 943e5db3f..297daed10 100644 --- a/src/locales/pt-PT.json +++ b/src/locales/pt-PT.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Transparente", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", + "black": "Preto", + "white": "Branco", + "red": "Vermelho", + "pink": "Rosa", + "grape": "Uva", + "violet": "Violeta", + "gray": "Cinza", + "blue": "Azul", "cyan": "", "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "green": "Verde", + "yellow": "Amarelo", + "orange": "Laranja", + "bronze": "Bronze" }, "welcomeScreen": { "app": { @@ -425,8 +425,8 @@ }, "colorPicker": { "mostUsedCustomColors": "", - "colors": "", - "shades": "", + "colors": "Cores", + "shades": "Tons", "hexCode": "", "noShades": "" } diff --git a/src/locales/ro-RO.json b/src/locales/ro-RO.json index 5440f8f72..d6d6c3c3e 100644 --- a/src/locales/ro-RO.json +++ b/src/locales/ro-RO.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Transparent", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Negru", + "white": "Alb", + "red": "Roșu", + "pink": "Roz", + "grape": "Struguriu", + "violet": "Violet", + "gray": "Gri", + "blue": "Albastru", + "cyan": "Cyan", + "teal": "Cyan-verde", + "green": "Verde", + "yellow": "Galben", + "orange": "Portocaliu", + "bronze": "Bronz" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Cele mai utilizate culori personalizate", + "colors": "Culori", + "shades": "Nuanțe", + "hexCode": "Cod hexa", + "noShades": "Nu este disponibilă nicio nuanță pentru această culoare" } } diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json index 7ba5b3374..2d2958d3c 100644 --- a/src/locales/ru-RU.json +++ b/src/locales/ru-RU.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Прозрачный", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Чёрный", + "white": "Белый", + "red": "Красный", + "pink": "Розовый", + "grape": "Виноградный", + "violet": "Фиолетовый", + "gray": "Серый", + "blue": "Синий", + "cyan": "Голубой", + "teal": "Бирюзовый", + "green": "Зелёный", + "yellow": "Жёлтый", + "orange": "Оранжевый", + "bronze": "Бронзовый" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Часто используемые пользовательские цвета", + "colors": "Цвета", + "shades": "Оттенки", + "hexCode": "Шестнадцатеричный код", + "noShades": "Нет доступных оттенков для этого цвета" } } diff --git a/src/locales/sk-SK.json b/src/locales/sk-SK.json index 2123d7c1a..c976091cc 100644 --- a/src/locales/sk-SK.json +++ b/src/locales/sk-SK.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Priehľadná", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Čierna", + "white": "Biela", + "red": "Červená", + "pink": "Ružová", + "grape": "Hroznová fialová", + "violet": "Fialová", + "gray": "Sivá", + "blue": "Modrá", + "cyan": "Azúrová", + "teal": "Modrozelená", + "green": "Zelená", + "yellow": "Žltá", + "orange": "Oranžová", + "bronze": "Bronzová" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Najpoužívanejšie vlastné farby", + "colors": "Farby", + "shades": "Odtiene", + "hexCode": "Hex kód", + "noShades": "Pre túto farbu nie sú dostupné žiadne odtiene" } } diff --git a/src/locales/sl-SI.json b/src/locales/sl-SI.json index 902b2476f..801a3bc03 100644 --- a/src/locales/sl-SI.json +++ b/src/locales/sl-SI.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Prosojno", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Črna", + "white": "Bela", + "red": "Rdeča", + "pink": "Roza", + "grape": "Grozdje", + "violet": "Vijolična", + "gray": "Siva", + "blue": "Modra", + "cyan": "Cijan", + "teal": "Turkizna", + "green": "Zelena", + "yellow": "Rumena", + "orange": "Oranžna", + "bronze": "Bronasta" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Najpogosteje uporabljene barve po meri", + "colors": "Barve", + "shades": "Odtenki", + "hexCode": "Hex koda", + "noShades": "Odtenki za to barvo niso na voljo" } } diff --git a/src/locales/sv-SE.json b/src/locales/sv-SE.json index 641e3ce66..de2e9982c 100644 --- a/src/locales/sv-SE.json +++ b/src/locales/sv-SE.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "Genomskinlig", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "Svart", + "white": "Vit", + "red": "Röd", + "pink": "Rosa", + "grape": "Lila", + "violet": "Violett", + "gray": "Grå", + "blue": "Blå", + "cyan": "Turkos", + "teal": "Blågrön", + "green": "Grön", + "yellow": "Gul", + "orange": "Orange", + "bronze": "Brons" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "Mest frekvent använda anpassade färger", + "colors": "Färger", + "shades": "Nyanser", + "hexCode": "Hex-kod", + "noShades": "Inga nyanser tillgängliga för denna färg" } } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 93ad2c948..50ba89073 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "透明", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "黑", + "white": "白", + "red": "红", + "pink": "粉红", + "grape": "紫红", + "violet": "蓝紫", + "gray": "灰", + "blue": "蓝", + "cyan": "青", + "teal": "蓝绿", + "green": "绿", + "yellow": "黄", + "orange": "橙", + "bronze": "古铜" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "常用自定义颜色", + "colors": "颜色", + "shades": "色调明暗", + "hexCode": "十六进制值", + "noShades": "此颜色没有可用的明暗变化" } } diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 3be58ef56..b86edb2bc 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -395,20 +395,20 @@ }, "colors": { "transparent": "透明", - "black": "", - "white": "", - "red": "", - "pink": "", - "grape": "", - "violet": "", - "gray": "", - "blue": "", - "cyan": "", - "teal": "", - "green": "", - "yellow": "", - "orange": "", - "bronze": "" + "black": "黑", + "white": "白", + "red": "紅", + "pink": "粉紅", + "grape": "深紫", + "violet": "藍紫", + "gray": "灰", + "blue": "藍", + "cyan": "青", + "teal": "藍綠", + "green": "綠", + "yellow": "黃", + "orange": "橘", + "bronze": "銅" }, "welcomeScreen": { "app": { @@ -424,10 +424,10 @@ } }, "colorPicker": { - "mostUsedCustomColors": "", - "colors": "", - "shades": "", - "hexCode": "", - "noShades": "" + "mostUsedCustomColors": "最常使用的自訂顏色", + "colors": "顏色", + "shades": "漸變色", + "hexCode": "Hex 碼", + "noShades": "沒有此顏色的漸變色" } } From 13780f390a668163504d245f88794206d458f199 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Wed, 24 May 2023 17:24:54 +0200 Subject: [PATCH 079/451] fix: add react v17 `useTransition` polyfill (#6618) --- src/components/LibraryMenuSection.tsx | 3 ++- src/hooks/useTransition.ts | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 src/hooks/useTransition.ts diff --git a/src/components/LibraryMenuSection.tsx b/src/components/LibraryMenuSection.tsx index d1af85481..b6866e1e9 100644 --- a/src/components/LibraryMenuSection.tsx +++ b/src/components/LibraryMenuSection.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useState, useTransition } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { LibraryUnit } from "./LibraryUnit"; import { LibraryItem } from "../types"; import Stack from "./Stack"; @@ -6,6 +6,7 @@ import clsx from "clsx"; import { ExcalidrawElement, NonDeleted } from "../element/types"; import { useAtom } from "jotai"; import { libraryItemSvgsCache } from "../hooks/useLibraryItemSvg"; +import { useTransition } from "../hooks/useTransition"; const ITEMS_PER_ROW = 4; const ROWS_RENDERED_PER_BATCH = 6; diff --git a/src/hooks/useTransition.ts b/src/hooks/useTransition.ts new file mode 100644 index 000000000..bb107edbc --- /dev/null +++ b/src/hooks/useTransition.ts @@ -0,0 +1,9 @@ +import React, { useCallback } from "react"; + +/** noop polyfill for v17. Subset of API available */ +function useTransitionPolyfill() { + const startTransition = useCallback((callback: () => void) => callback(), []); + return [false, startTransition] as const; +} + +export const useTransition = React.useTransition || useTransitionPolyfill; From 75bea48b5487339abb3bd017731d5a291bd3fba1 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Wed, 24 May 2023 22:52:21 +0200 Subject: [PATCH 080/451] fix: export dialog shortcut toggles console on firefox (#6620) --- src/components/App.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/App.tsx b/src/components/App.tsx index e6f961698..49919c957 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2156,6 +2156,7 @@ class App extends React.Component { event.shiftKey && event[KEYS.CTRL_OR_CMD] ) { + event.preventDefault(); this.setState({ openDialog: "imageExport" }); return; } From 6459ccda6aca3246832dbe9a4434839952b703b7 Mon Sep 17 00:00:00 2001 From: Alex Kim <45559664+alex-kim-dev@users.noreply.github.com> Date: Thu, 25 May 2023 19:27:41 +0500 Subject: [PATCH 081/451] feat: add flipping for multiple elements (#5578) * feat: add flipping when resizing multiple elements * fix: image elements not flipping its content * test: fix accidental resizing in grouping test * fix: angles not flipping vertically when resizing * feat: add flipping multiple elements with a command * revert: image elements not flipping its content This reverts commit cb989a6c66e62a02a8c04ce41f12507806c8d0a0. * fix: add special cases for flipping text & images * fix: a few corner cases for flipping * fix: remove angle flip * fix: bound text scaling when resizing * fix: linear elements drifting away after multiple flips * revert: fix linear elements drifting away after multiple flips This reverts commit bffc33dd3ffe56c72029eee6aca843d992bac7ab. * fix: linear elements unstable bounds * revert: linear elements unstable bounds This reverts commit 22ae9b02c4a49f0ed6448c27abe1969cf6abb1e3. * fix: hand-drawn lines shift after flipping * test: fix flipping tests * test: fix the number of context menu items * fix: incorrect scaling due to ignoring bound text when finding selection bounds * fix: bound text coordinates not being updated * fix: lines bound text rotation * fix: incorrect placement of bound lines on flip * remove redundant predicates in actionFlip * update test * refactor resizeElement with some renaming and comments * fix grouped bounded text elements not being flipped correctly * combine mutation for bounded text element * remove incorrect return * fix: linear elements bindings after flipping * revert: remove incorrect return This reverts commit e6b205ca900b504fe982e4ac1b3b19dcfca246b8. * fix: minimum size for all elements in selection --------- Co-authored-by: Ryan Di --- src/actions/actionFlip.ts | 204 ++--------------- src/element/resizeElements.ts | 210 +++++++++++++----- .../__snapshots__/contextmenu.test.tsx.snap | 10 - .../regressionTests.test.tsx.snap | 17 +- src/tests/contextmenu.test.tsx | 4 + src/tests/flip.test.tsx | 75 ++++--- src/tests/regressionTests.test.tsx | 2 +- 7 files changed, 240 insertions(+), 282 deletions(-) diff --git a/src/actions/actionFlip.ts b/src/actions/actionFlip.ts index 0dadc23b1..8edbbc4aa 100644 --- a/src/actions/actionFlip.ts +++ b/src/actions/actionFlip.ts @@ -1,42 +1,17 @@ import { register } from "./register"; import { getSelectedElements } from "../scene"; import { getNonDeletedElements } from "../element"; -import { mutateElement } from "../element/mutateElement"; import { ExcalidrawElement, NonDeleted } from "../element/types"; -import { normalizeAngle, resizeSingleElement } from "../element/resizeElements"; -import { AppState } from "../types"; -import { getTransformHandles } from "../element/transformHandles"; -import { updateBoundElements } from "../element/binding"; +import { resizeMultipleElements } from "../element/resizeElements"; +import { AppState, PointerDownState } from "../types"; import { arrayToMap } from "../utils"; -import { - getElementAbsoluteCoords, - getElementPointsCoords, -} from "../element/bounds"; -import { isLinearElement } from "../element/typeChecks"; -import { LinearElementEditor } from "../element/linearElementEditor"; import { CODES, KEYS } from "../keys"; - -const enableActionFlipHorizontal = ( - elements: readonly ExcalidrawElement[], - appState: AppState, -) => { - const eligibleElements = getSelectedElements( - getNonDeletedElements(elements), - appState, - ); - return eligibleElements.length === 1 && eligibleElements[0].type !== "text"; -}; - -const enableActionFlipVertical = ( - elements: readonly ExcalidrawElement[], - appState: AppState, -) => { - const eligibleElements = getSelectedElements( - getNonDeletedElements(elements), - appState, - ); - return eligibleElements.length === 1; -}; +import { getCommonBoundingBox } from "../element/bounds"; +import { + bindOrUnbindSelectedElements, + isBindingEnabled, + unbindLinearElements, +} from "../element/binding"; export const actionFlipHorizontal = register({ name: "flipHorizontal", @@ -50,8 +25,6 @@ export const actionFlipHorizontal = register({ }, keyTest: (event) => event.shiftKey && event.code === CODES.H, contextItemLabel: "labels.flipHorizontal", - predicate: (elements, appState) => - enableActionFlipHorizontal(elements, appState), }); export const actionFlipVertical = register({ @@ -67,8 +40,6 @@ export const actionFlipVertical = register({ keyTest: (event) => event.shiftKey && event.code === CODES.V && !event[KEYS.CTRL_OR_CMD], contextItemLabel: "labels.flipVertical", - predicate: (elements, appState) => - enableActionFlipVertical(elements, appState), }); const flipSelectedElements = ( @@ -81,11 +52,6 @@ const flipSelectedElements = ( appState, ); - // remove once we allow for groups of elements to be flipped - if (selectedElements.length > 1) { - return elements; - } - const updatedElements = flipElements( selectedElements, appState, @@ -104,144 +70,20 @@ const flipElements = ( appState: AppState, flipDirection: "horizontal" | "vertical", ): ExcalidrawElement[] => { - elements.forEach((element) => { - flipElement(element, appState); - // If vertical flip, rotate an extra 180 - if (flipDirection === "vertical") { - rotateElement(element, Math.PI); - } - }); + const { minX, minY, maxX, maxY } = getCommonBoundingBox(elements); + + resizeMultipleElements( + { originalElements: arrayToMap(elements) } as PointerDownState, + elements, + "nw", + true, + flipDirection === "horizontal" ? maxX : minX, + flipDirection === "horizontal" ? minY : maxY, + ); + + (isBindingEnabled(appState) + ? bindOrUnbindSelectedElements + : unbindLinearElements)(elements); + return elements; }; - -const flipElement = ( - element: NonDeleted, - appState: AppState, -) => { - const originalX = element.x; - const originalY = element.y; - const width = element.width; - const height = element.height; - const originalAngle = normalizeAngle(element.angle); - - // Rotate back to zero, if necessary - mutateElement(element, { - angle: normalizeAngle(0), - }); - // Flip unrotated by pulling TransformHandle to opposite side - const transformHandles = getTransformHandles(element, appState.zoom); - let usingNWHandle = true; - let nHandle = transformHandles.nw; - if (!nHandle) { - // Use ne handle instead - usingNWHandle = false; - nHandle = transformHandles.ne; - if (!nHandle) { - mutateElement(element, { - angle: originalAngle, - }); - return; - } - } - - let finalOffsetX = 0; - if (isLinearElement(element) && element.points.length < 3) { - finalOffsetX = - element.points.reduce((max, point) => Math.max(max, point[0]), 0) * 2 - - element.width; - } - - let initialPointsCoords; - if (isLinearElement(element)) { - initialPointsCoords = getElementPointsCoords(element, element.points); - } - const initialElementAbsoluteCoords = getElementAbsoluteCoords(element); - - if (isLinearElement(element) && element.points.length < 3) { - for (let index = 1; index < element.points.length; index++) { - LinearElementEditor.movePoints(element, [ - { - index, - point: [-element.points[index][0], element.points[index][1]], - }, - ]); - } - LinearElementEditor.normalizePoints(element); - } else { - const elWidth = initialPointsCoords - ? initialPointsCoords[2] - initialPointsCoords[0] - : initialElementAbsoluteCoords[2] - initialElementAbsoluteCoords[0]; - - const startPoint = initialPointsCoords - ? [initialPointsCoords[0], initialPointsCoords[1]] - : [initialElementAbsoluteCoords[0], initialElementAbsoluteCoords[1]]; - - resizeSingleElement( - new Map().set(element.id, element), - false, - element, - usingNWHandle ? "nw" : "ne", - true, - usingNWHandle ? startPoint[0] + elWidth : startPoint[0] - elWidth, - startPoint[1], - ); - } - - // Rotate by (360 degrees - original angle) - let angle = normalizeAngle(2 * Math.PI - originalAngle); - if (angle < 0) { - // check, probably unnecessary - angle = normalizeAngle(angle + 2 * Math.PI); - } - mutateElement(element, { - angle, - }); - - // Move back to original spot to appear "flipped in place" - mutateElement(element, { - x: originalX + finalOffsetX, - y: originalY, - width, - height, - }); - - updateBoundElements(element); - - if (initialPointsCoords && isLinearElement(element)) { - // Adjusting origin because when a beizer curve path exceeds min/max points it offsets the origin. - // There's still room for improvement since when the line roughness is > 1 - // we still have a small offset of the origin when fliipping the element. - const finalPointsCoords = getElementPointsCoords(element, element.points); - - const topLeftCoordsDiff = initialPointsCoords[0] - finalPointsCoords[0]; - const topRightCoordDiff = initialPointsCoords[2] - finalPointsCoords[2]; - - const coordsDiff = topLeftCoordsDiff + topRightCoordDiff; - - mutateElement(element, { - x: element.x + coordsDiff * 0.5, - y: element.y, - width, - height, - }); - } -}; - -const rotateElement = (element: ExcalidrawElement, rotationAngle: number) => { - const originalX = element.x; - const originalY = element.y; - let angle = normalizeAngle(element.angle + rotationAngle); - if (angle < 0) { - // check, probably unnecessary - angle = normalizeAngle(2 * Math.PI + angle); - } - mutateElement(element, { - angle, - }); - - // Move back to original spot - mutateElement(element, { - x: originalX, - y: originalY, - }); -}; diff --git a/src/element/resizeElements.ts b/src/element/resizeElements.ts index 67a6346be..3610d7577 100644 --- a/src/element/resizeElements.ts +++ b/src/element/resizeElements.ts @@ -14,17 +14,21 @@ import { NonDeleted, ExcalidrawElement, ExcalidrawTextElementWithContainer, + ExcalidrawImageElement, } from "./types"; +import type { Mutable } from "../utility-types"; import { getElementAbsoluteCoords, getCommonBounds, getResizedElementAbsoluteCoords, getCommonBoundingBox, + getElementPointsCoords, } from "./bounds"; import { isArrowElement, isBoundToContainer, isFreeDrawElement, + isImageElement, isLinearElement, isTextElement, } from "./typeChecks"; @@ -49,8 +53,12 @@ import { measureText, getBoundTextMaxHeight, } from "./textElement"; +import { LinearElementEditor } from "./linearElementEditor"; export const normalizeAngle = (angle: number): number => { + if (angle < 0) { + return angle + 2 * Math.PI; + } if (angle >= 2 * Math.PI) { return angle - 2 * Math.PI; } @@ -596,7 +604,7 @@ export const resizeSingleElement = ( } }; -const resizeMultipleElements = ( +export const resizeMultipleElements = ( pointerDownState: PointerDownState, selectedElements: readonly NonDeletedExcalidrawElement[], transformHandleType: "nw" | "ne" | "sw" | "se", @@ -627,8 +635,28 @@ const resizeMultipleElements = ( [], ); + // getCommonBoundingBox() uses getBoundTextElement() which returns null for + // original elements from pointerDownState, so we have to find and add these + // bound text elements manually. Additionally, the coordinates of bound text + // elements aren't always up to date. + const boundTextElements = targetElements.reduce((acc, { orig }) => { + if (!isLinearElement(orig)) { + return acc; + } + const textId = getBoundTextElementId(orig); + if (!textId) { + return acc; + } + const text = pointerDownState.originalElements.get(textId) ?? null; + if (!isBoundToContainer(text)) { + return acc; + } + const xy = LinearElementEditor.getBoundTextElementPosition(orig, text); + return [...acc, { ...text, ...xy }]; + }, [] as ExcalidrawTextElementWithContainer[]); + const { minX, minY, maxX, maxY, midX, midY } = getCommonBoundingBox( - targetElements.map(({ orig }) => orig), + targetElements.map(({ orig }) => orig).concat(boundTextElements), ); const direction = transformHandleType; @@ -640,12 +668,22 @@ const resizeMultipleElements = ( }; // anchor point must be on the opposite side of the dragged selection handle - // or be the center of the selection if alt is pressed + // or be the center of the selection if shouldResizeFromCenter const [anchorX, anchorY]: Point = shouldResizeFromCenter ? [midX, midY] : mapDirectionsToAnchors[direction]; - const mapDirectionsToPointerSides: Record< + const scale = + Math.max( + Math.abs(pointerX - anchorX) / (maxX - minX) || 0, + Math.abs(pointerY - anchorY) / (maxY - minY) || 0, + ) * (shouldResizeFromCenter ? 2 : 1); + + if (scale === 0) { + return; + } + + const mapDirectionsToPointerPositions: Record< typeof direction, [x: boolean, y: boolean] > = { @@ -655,68 +693,117 @@ const resizeMultipleElements = ( nw: [pointerX <= anchorX, pointerY <= anchorY], }; - // pointer side relative to anchor - const [pointerSideX, pointerSideY] = mapDirectionsToPointerSides[ + /** + * to flip an element: + * 1. determine over which axis is the element being flipped + * (could be x, y, or both) indicated by `flipFactorX` & `flipFactorY` + * 2. shift element's position by the amount of width or height (or both) or + * mirror points in the case of linear & freedraw elemenets + * 3. adjust element angle + */ + const [flipFactorX, flipFactorY] = mapDirectionsToPointerPositions[ direction ].map((condition) => (condition ? 1 : -1)); + const isFlippedByX = flipFactorX < 0; + const isFlippedByY = flipFactorY < 0; - // stop resizing if a pointer is on the other side of selection - if (pointerSideX < 0 && pointerSideY < 0) { - return; - } + const elementsAndUpdates: { + element: NonDeletedExcalidrawElement; + update: Mutable< + Pick + > & { + points?: ExcalidrawLinearElement["points"]; + fontSize?: ExcalidrawTextElement["fontSize"]; + baseline?: ExcalidrawTextElement["baseline"]; + scale?: ExcalidrawImageElement["scale"]; + }; + boundText: { + element: ExcalidrawTextElementWithContainer; + fontSize: ExcalidrawTextElement["fontSize"]; + baseline: ExcalidrawTextElement["baseline"]; + } | null; + }[] = []; - const scale = - Math.max( - (pointerSideX * Math.abs(pointerX - anchorX)) / (maxX - minX), - (pointerSideY * Math.abs(pointerY - anchorY)) / (maxY - minY), - ) * (shouldResizeFromCenter ? 2 : 1); + for (const { orig, latest } of targetElements) { + // bounded text elements are updated along with their container elements + if (isTextElement(orig) && isBoundToContainer(orig)) { + continue; + } - if (scale === 0) { - return; - } + const width = orig.width * scale; + const height = orig.height * scale; + const angle = normalizeAngle(orig.angle * flipFactorX * flipFactorY); - targetElements.forEach((element) => { - const width = element.orig.width * scale; - const height = element.orig.height * scale; - const x = anchorX + (element.orig.x - anchorX) * scale; - const y = anchorY + (element.orig.y - anchorY) * scale; + const isLinearOrFreeDraw = isLinearElement(orig) || isFreeDrawElement(orig); + const offsetX = orig.x - anchorX; + const offsetY = orig.y - anchorY; + const shiftX = isFlippedByX && !isLinearOrFreeDraw ? width : 0; + const shiftY = isFlippedByY && !isLinearOrFreeDraw ? height : 0; + const x = anchorX + flipFactorX * (offsetX * scale + shiftX); + const y = anchorY + flipFactorY * (offsetY * scale + shiftY); - // readjust points for linear & free draw elements const rescaledPoints = rescalePointsInElement( - element.orig, - width, - height, + orig, + width * flipFactorX, + height * flipFactorY, false, ); - const update: { - width: number; - height: number; - x: number; - y: number; - points?: Point[]; - fontSize?: number; - baseline?: number; - } = { - width, - height, + const update: typeof elementsAndUpdates[0]["update"] = { x, y, + width, + height, + angle, ...rescaledPoints, }; - let boundTextUpdates: { fontSize: number; baseline: number } | null = null; + if (isImageElement(orig) && targetElements.length === 1) { + update.scale = [orig.scale[0] * flipFactorX, orig.scale[1] * flipFactorY]; + } - const boundTextElement = getBoundTextElement(element.latest); + if (isLinearElement(orig) && (isFlippedByX || isFlippedByY)) { + const origBounds = getElementPointsCoords(orig, orig.points); + const newBounds = getElementPointsCoords( + { ...orig, x, y }, + rescaledPoints.points!, + ); + const origXY = [orig.x, orig.y]; + const newXY = [x, y]; - if (boundTextElement || isTextElement(element.orig)) { + const linearShift = (axis: "x" | "y") => { + const i = axis === "x" ? 0 : 1; + return ( + (newBounds[i + 2] - + newXY[i] - + (origXY[i] - origBounds[i]) * scale + + (origBounds[i + 2] - origXY[i]) * scale - + (newXY[i] - newBounds[i])) / + 2 + ); + }; + + if (isFlippedByX) { + update.x -= linearShift("x"); + } + + if (isFlippedByY) { + update.y -= linearShift("y"); + } + } + + let boundText: typeof elementsAndUpdates[0]["boundText"] = null; + + const boundTextElement = getBoundTextElement(latest); + + if (boundTextElement || isTextElement(orig)) { const updatedElement = { - ...element.latest, + ...latest, width, height, }; const metrics = measureFontSizeFromWidth( - boundTextElement ?? (element.orig as ExcalidrawTextElement), + boundTextElement ?? (orig as ExcalidrawTextElement), boundTextElement ? getBoundTextMaxWidth(updatedElement) : updatedElement.width, @@ -729,29 +816,50 @@ const resizeMultipleElements = ( return; } - if (isTextElement(element.orig)) { + if (isTextElement(orig)) { update.fontSize = metrics.size; update.baseline = metrics.baseline; } if (boundTextElement) { - boundTextUpdates = { + boundText = { + element: boundTextElement, fontSize: metrics.size, baseline: metrics.baseline, }; } } - updateBoundElements(element.latest, { newSize: { width, height } }); + elementsAndUpdates.push({ element: latest, update, boundText }); + } - mutateElement(element.latest, update); + const elementsToUpdate = elementsAndUpdates.map(({ element }) => element); - if (boundTextElement && boundTextUpdates) { - mutateElement(boundTextElement, boundTextUpdates); + for (const { element, update, boundText } of elementsAndUpdates) { + const { width, height, angle } = update; - handleBindTextResize(element.latest, transformHandleType); + mutateElement(element, update, false); + + updateBoundElements(element, { + simultaneouslyUpdated: elementsToUpdate, + newSize: { width, height }, + }); + + if (boundText) { + const { element: boundTextElement, ...boundTextUpdates } = boundText; + mutateElement( + boundTextElement, + { + ...boundTextUpdates, + angle: isLinearElement(element) ? undefined : angle, + }, + false, + ); + handleBindTextResize(element, transformHandleType); } - }); + } + + Scene.getScene(elementsAndUpdates[0].element)?.informMutation(); }; const rotateMultipleElements = ( diff --git a/src/tests/__snapshots__/contextmenu.test.tsx.snap b/src/tests/__snapshots__/contextmenu.test.tsx.snap index 5e3a5b221..6103c2f51 100644 --- a/src/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/src/tests/__snapshots__/contextmenu.test.tsx.snap @@ -197,7 +197,6 @@ Object { "keyTest": [Function], "name": "flipHorizontal", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -207,7 +206,6 @@ Object { "keyTest": [Function], "name": "flipVertical", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -4594,7 +4592,6 @@ Object { "keyTest": [Function], "name": "flipHorizontal", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -4604,7 +4601,6 @@ Object { "keyTest": [Function], "name": "flipVertical", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -5144,7 +5140,6 @@ Object { "keyTest": [Function], "name": "flipHorizontal", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -5154,7 +5149,6 @@ Object { "keyTest": [Function], "name": "flipVertical", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -6003,7 +5997,6 @@ Object { "keyTest": [Function], "name": "flipHorizontal", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -6013,7 +6006,6 @@ Object { "keyTest": [Function], "name": "flipVertical", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -6349,7 +6341,6 @@ Object { "keyTest": [Function], "name": "flipHorizontal", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, @@ -6359,7 +6350,6 @@ Object { "keyTest": [Function], "name": "flipVertical", "perform": [Function], - "predicate": [Function], "trackEvent": Object { "category": "element", }, diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index 68d87ef33..931a2db5a 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -15332,7 +15332,10 @@ Object { "penMode": false, "pendingImageElementId": null, "previousSelectedElementIds": Object { + "id0": true, + "id1": true, "id2": true, + "id3": true, }, "resizingElement": null, "scrollX": 0, @@ -15342,7 +15345,6 @@ Object { "id0": true, "id1": true, "id2": true, - "id3": true, "id5": true, }, "selectedGroupIds": Object {}, @@ -15390,7 +15392,7 @@ Object { "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 1505387817, + "versionNonce": 23633383, "width": 10, "x": 10, "y": 10, @@ -15421,7 +15423,7 @@ Object { "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 23633383, + "versionNonce": 493213705, "width": 10, "x": 30, "y": 10, @@ -15452,7 +15454,7 @@ Object { "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 493213705, + "versionNonce": 915032327, "width": 10, "x": 50, "y": 10, @@ -15803,7 +15805,6 @@ Object { "id0": true, "id1": true, "id2": true, - "id3": true, "id5": true, }, "selectedGroupIds": Object {}, @@ -15833,7 +15834,7 @@ Object { "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 1505387817, + "versionNonce": 23633383, "width": 10, "x": 10, "y": 10, @@ -15861,7 +15862,7 @@ Object { "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 23633383, + "versionNonce": 493213705, "width": 10, "x": 30, "y": 10, @@ -15889,7 +15890,7 @@ Object { "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 493213705, + "versionNonce": 915032327, "width": 10, "x": 50, "y": 10, diff --git a/src/tests/contextmenu.test.tsx b/src/tests/contextmenu.test.tsx index 9b4007b03..9e89996af 100644 --- a/src/tests/contextmenu.test.tsx +++ b/src/tests/contextmenu.test.tsx @@ -207,6 +207,8 @@ describe("contextMenu element", () => { "deleteSelectedElements", "group", "addToLibrary", + "flipHorizontal", + "flipVertical", "sendBackward", "bringForward", "sendToBack", @@ -258,6 +260,8 @@ describe("contextMenu element", () => { "deleteSelectedElements", "ungroup", "addToLibrary", + "flipHorizontal", + "flipVertical", "sendBackward", "bringForward", "sendToBack", diff --git a/src/tests/flip.test.tsx b/src/tests/flip.test.tsx index c1469bc83..091d1c73b 100644 --- a/src/tests/flip.test.tsx +++ b/src/tests/flip.test.tsx @@ -195,10 +195,8 @@ const checkElementsBoundingBox = async ( debugger; await waitFor(() => { // Check if width and height did not change - expect(x1 - toleranceInPx <= x12 && x12 <= x1 + toleranceInPx).toBeTruthy(); - expect(y1 - toleranceInPx <= y12 && y12 <= y1 + toleranceInPx).toBeTruthy(); - expect(x2 - toleranceInPx <= x22 && x22 <= x2 + toleranceInPx).toBeTruthy(); - expect(y2 - toleranceInPx <= y22 && y22 <= y2 + toleranceInPx).toBeTruthy(); + expect(x2 - x1).toBeCloseTo(x22 - x12, -1); + expect(y2 - y1).toBeCloseTo(y22 - y12, -1); }); }; @@ -216,14 +214,22 @@ const checkTwoPointsLineHorizontalFlip = async () => { h.app.actionManager.executeAction(actionFlipHorizontal); const newElement = h.elements[0] as ExcalidrawLinearElement; await waitFor(() => { - expect(originalElement.points[0][0]).toEqual( - newElement.points[0][0] !== 0 ? -newElement.points[0][0] : 0, + expect(originalElement.points[0][0]).toBeCloseTo( + -newElement.points[0][0], + 5, ); - expect(originalElement.points[0][1]).toEqual(newElement.points[0][1]); - expect(originalElement.points[1][0]).toEqual( - newElement.points[1][0] !== 0 ? -newElement.points[1][0] : 0, + expect(originalElement.points[0][1]).toBeCloseTo( + newElement.points[0][1], + 5, + ); + expect(originalElement.points[1][0]).toBeCloseTo( + -newElement.points[1][0], + 5, + ); + expect(originalElement.points[1][1]).toBeCloseTo( + newElement.points[1][1], + 5, ); - expect(originalElement.points[1][1]).toEqual(newElement.points[1][1]); }); }; @@ -234,14 +240,22 @@ const checkTwoPointsLineVerticalFlip = async () => { h.app.actionManager.executeAction(actionFlipVertical); const newElement = h.elements[0] as ExcalidrawLinearElement; await waitFor(() => { - expect(originalElement.points[0][0]).toEqual( - newElement.points[0][0] !== 0 ? -newElement.points[0][0] : 0, + expect(originalElement.points[0][0]).toBeCloseTo( + newElement.points[0][0], + 5, ); - expect(originalElement.points[0][1]).toEqual(newElement.points[0][1]); - expect(originalElement.points[1][0]).toEqual( - newElement.points[1][0] !== 0 ? -newElement.points[1][0] : 0, + expect(originalElement.points[0][1]).toBeCloseTo( + -newElement.points[0][1], + 5, + ); + expect(originalElement.points[1][0]).toBeCloseTo( + newElement.points[1][0], + 5, + ); + expect(originalElement.points[1][1]).toBeCloseTo( + -newElement.points[1][1], + 5, ); - expect(originalElement.points[1][1]).toEqual(newElement.points[1][1]); }); }; @@ -318,7 +332,7 @@ describe("rectangle", () => { it("flips a rotated rectangle vertically correctly", async () => { const originalAngle = (3 * Math.PI) / 4; - const expectedAgnle = Math.PI / 4; + const expectedAgnle = (5 * Math.PI) / 4; createAndSelectOneRectangle(originalAngle); @@ -351,7 +365,7 @@ describe("diamond", () => { it("flips a rotated diamond vertically correctly", async () => { const originalAngle = (5 * Math.PI) / 4; - const expectedAngle = (7 * Math.PI) / 4; + const expectedAngle = (3 * Math.PI) / 4; createAndSelectOneDiamond(originalAngle); @@ -384,7 +398,7 @@ describe("ellipse", () => { it("flips a rotated ellipse vertically correctly", async () => { const originalAngle = (7 * Math.PI) / 4; - const expectedAngle = (5 * Math.PI) / 4; + const expectedAngle = Math.PI / 4; createAndSelectOneEllipse(originalAngle); @@ -429,7 +443,7 @@ describe("arrow", () => { it("flips a rotated arrow vertically with line inside min/max points bounds", async () => { const originalAngle = Math.PI / 4; - const expectedAngle = (3 * Math.PI) / 4; + const expectedAngle = (7 * Math.PI) / 4; const line = createLinearElementWithCurveInsideMinMaxPoints("arrow"); h.app.scene.replaceAllElements([line]); h.app.state.selectedElementIds[line.id] = true; @@ -481,7 +495,7 @@ describe("arrow", () => { //TODO: elements with curve outside minMax points have a wrong bounding box!!! it.skip("flips a rotated arrow vertically with line outside min/max points bounds", async () => { const originalAngle = Math.PI / 4; - const expectedAngle = (3 * Math.PI) / 4; + const expectedAngle = (7 * Math.PI) / 4; const line = createLinearElementsWithCurveOutsideMinMaxPoints("arrow"); mutateElement(line, { angle: originalAngle }); h.app.scene.replaceAllElements([line]); @@ -512,7 +526,6 @@ describe("arrow", () => { it("flips a two points arrow vertically correctly", async () => { createAndSelectOneArrow(); - await checkTwoPointsLineVerticalFlip(); }); }); @@ -581,7 +594,7 @@ describe("line", () => { //TODO: elements with curve outside minMax points have a wrong bounding box it.skip("flips a rotated line vertically with line outside min/max points bounds", async () => { const originalAngle = Math.PI / 4; - const expectedAngle = (3 * Math.PI) / 4; + const expectedAngle = (7 * Math.PI) / 4; const line = createLinearElementsWithCurveOutsideMinMaxPoints("line"); mutateElement(line, { angle: originalAngle }); h.app.scene.replaceAllElements([line]); @@ -616,7 +629,7 @@ describe("line", () => { it("flips a rotated line vertically with line inside min/max points bounds", async () => { const originalAngle = Math.PI / 4; - const expectedAngle = (3 * Math.PI) / 4; + const expectedAngle = (7 * Math.PI) / 4; const line = createLinearElementWithCurveInsideMinMaxPoints("line"); h.app.scene.replaceAllElements([line]); h.app.state.selectedElementIds[line.id] = true; @@ -670,7 +683,7 @@ describe("freedraw", () => { it("flips a rotated drawing vertically correctly", async () => { const originalAngle = Math.PI / 4; - const expectedAngle = (3 * Math.PI) / 4; + const expectedAngle = (7 * Math.PI) / 4; const draw = createAndReturnOneDraw(originalAngle); // select draw, since not done automatically @@ -718,8 +731,8 @@ describe("image", () => { }); await checkVerticalFlip(); - expect((h.elements[0] as ExcalidrawImageElement).scale).toEqual([-1, 1]); - expect(h.elements[0].angle).toBeCloseTo(Math.PI); + expect((h.elements[0] as ExcalidrawImageElement).scale).toEqual([1, -1]); + expect(h.elements[0].angle).toBeCloseTo(0); }); it("flips an rotated image horizontally correctly", async () => { @@ -742,7 +755,7 @@ describe("image", () => { it("flips an rotated image vertically correctly", async () => { const originalAngle = Math.PI / 4; - const expectedAngle = (3 * Math.PI) / 4; + const expectedAngle = (7 * Math.PI) / 4; //paste image await createImage(); await waitFor(() => { @@ -757,7 +770,7 @@ describe("image", () => { }); await checkRotatedVerticalFlip(expectedAngle); - expect((h.elements[0] as ExcalidrawImageElement).scale).toEqual([-1, 1]); + expect((h.elements[0] as ExcalidrawImageElement).scale).toEqual([1, -1]); expect(h.elements[0].angle).toBeCloseTo(expectedAngle); }); @@ -772,7 +785,7 @@ describe("image", () => { }); await checkVerticalHorizontalFlip(); - expect((h.elements[0] as ExcalidrawImageElement).scale).toEqual([1, 1]); - expect(h.elements[0].angle).toBeCloseTo(Math.PI); + expect((h.elements[0] as ExcalidrawImageElement).scale).toEqual([-1, -1]); + expect(h.elements[0].angle).toBeCloseTo(0); }); }); diff --git a/src/tests/regressionTests.test.tsx b/src/tests/regressionTests.test.tsx index 9ecbfb42c..2b9094888 100644 --- a/src/tests/regressionTests.test.tsx +++ b/src/tests/regressionTests.test.tsx @@ -542,7 +542,7 @@ describe("regression tests", () => { expect(element.groupIds.length).toBe(1); } - mouse.reset(); + mouse.moveTo(-10, -10); // the NW resizing handle is at [0, 0], so moving further mouse.down(); mouse.restorePosition(...end); mouse.up(); From 08563e7d7bd30db16d09da47b40b8faae176d998 Mon Sep 17 00:00:00 2001 From: Are Date: Fri, 26 May 2023 16:16:55 +0200 Subject: [PATCH 082/451] feat: update design of ImageExportDialog (#6614) Co-authored-by: dwelle --- src/actions/actionExport.tsx | 3 +- src/actions/manager.tsx | 7 +- src/components/ConfirmDialog.tsx | 2 +- src/components/Dialog.scss | 29 ++ src/components/Dialog.tsx | 33 +- src/components/ErrorDialog.tsx | 2 +- src/components/ImageExportDialog.scss | 215 ++++++++++++ src/components/ImageExportDialog.tsx | 360 +++++++++++++------- src/components/LibraryMenuHeaderContent.tsx | 2 +- src/components/Modal.scss | 19 +- src/components/Modal.tsx | 2 +- src/components/PasteChartDialog.tsx | 2 +- src/components/ProjectName.tsx | 5 +- src/components/RadioGroup.scss | 100 ++++++ src/components/RadioGroup.tsx | 42 +++ src/components/Switch.scss | 116 +++++++ src/components/Switch.tsx | 38 +++ src/components/icons.tsx | 29 ++ src/excalidraw-app/collab/RoomDialog.tsx | 2 +- src/locales/en.json | 33 +- src/tests/packages/excalidraw.test.tsx | 11 +- 21 files changed, 881 insertions(+), 171 deletions(-) create mode 100644 src/components/ImageExportDialog.scss create mode 100644 src/components/RadioGroup.scss create mode 100644 src/components/RadioGroup.tsx create mode 100644 src/components/Switch.scss create mode 100644 src/components/Switch.tsx diff --git a/src/actions/actionExport.tsx b/src/actions/actionExport.tsx index f142eac87..d945ba959 100644 --- a/src/actions/actionExport.tsx +++ b/src/actions/actionExport.tsx @@ -26,7 +26,7 @@ export const actionChangeProjectName = register({ perform: (_elements, appState, value) => { return { appState: { ...appState, name: value }, commitToHistory: false }; }, - PanelComponent: ({ appState, updateData, appProps }) => ( + PanelComponent: ({ appState, updateData, appProps, data }) => ( ), }); diff --git a/src/actions/manager.tsx b/src/actions/manager.tsx index 60648e410..e52e91da7 100644 --- a/src/actions/manager.tsx +++ b/src/actions/manager.tsx @@ -118,10 +118,13 @@ export class ActionManager { return true; } - executeAction(action: Action, source: ActionSource = "api") { + executeAction( + action: Action, + source: ActionSource = "api", + value: any = null, + ) { const elements = this.getElementsIncludingDeleted(); const appState = this.getAppState(); - const value = null; trackAction(action, source, appState, elements, this.app, value); diff --git a/src/components/ConfirmDialog.tsx b/src/components/ConfirmDialog.tsx index a0f257e36..9061fefa0 100644 --- a/src/components/ConfirmDialog.tsx +++ b/src/components/ConfirmDialog.tsx @@ -31,7 +31,7 @@ const ConfirmDialog = (props: Props) => { return ( diff --git a/src/components/Dialog.scss b/src/components/Dialog.scss index 604b3c64e..405f9235a 100644 --- a/src/components/Dialog.scss +++ b/src/components/Dialog.scss @@ -14,4 +14,33 @@ padding: 0 0 0.75rem; margin-bottom: 1.5rem; } + + .Dialog__close { + color: var(--color-gray-40); + margin: 0; + position: absolute; + top: 0.75rem; + right: 0.5rem; + border: 0; + background-color: transparent; + line-height: 0; + cursor: pointer; + + &:hover { + color: var(--color-gray-60); + } + &:active { + color: var(--color-gray-40); + } + + @include isMobile { + top: 1.25rem; + right: 1.25rem; + } + + svg { + width: 1.5rem; + height: 1.5rem; + } + } } diff --git a/src/components/Dialog.tsx b/src/components/Dialog.tsx index 363bb849f..a76f65e46 100644 --- a/src/components/Dialog.tsx +++ b/src/components/Dialog.tsx @@ -21,9 +21,9 @@ import { jotaiScope } from "../jotai"; export interface DialogProps { children: React.ReactNode; className?: string; - small?: boolean; + size?: "small" | "regular" | "wide"; onCloseRequest(): void; - title: React.ReactNode; + title: React.ReactNode | false; autofocus?: boolean; theme?: AppState["theme"]; closeOnClickOutside?: boolean; @@ -33,6 +33,7 @@ export const Dialog = (props: DialogProps) => { const [islandNode, setIslandNode] = useCallbackRefState(); const [lastActiveElement] = useState(document.activeElement); const { id } = useExcalidrawContainer(); + const device = useDevice(); useEffect(() => { if (!islandNode) { @@ -86,23 +87,27 @@ export const Dialog = (props: DialogProps) => { -

- {props.title} - -

+ {props.title && ( +

+ {props.title} +

+ )} +
{props.children}
diff --git a/src/components/ErrorDialog.tsx b/src/components/ErrorDialog.tsx index 56c303c15..74d265f73 100644 --- a/src/components/ErrorDialog.tsx +++ b/src/components/ErrorDialog.tsx @@ -28,7 +28,7 @@ export const ErrorDialog = ({ <> {modalIsShown && ( diff --git a/src/components/ImageExportDialog.scss b/src/components/ImageExportDialog.scss new file mode 100644 index 000000000..a74cfdc20 --- /dev/null +++ b/src/components/ImageExportDialog.scss @@ -0,0 +1,215 @@ +@import "../css/variables.module"; + +.excalidraw { + --ImageExportModal-preview-border: #d6d6d6; + + &.theme--dark { + --ImageExportModal-preview-border: #5c5c5c; + } + + .ImageExportModal { + display: flex; + flex-direction: row; + justify-content: space-between; + + & h3 { + font-family: "Assistant"; + font-style: normal; + font-weight: 700; + font-size: 1.313rem; + line-height: 130%; + padding: 0; + margin: 0; + + @include isMobile { + display: none; + } + } + + & > h3 { + display: none; + + @include isMobile { + display: block; + } + } + + @include isMobile { + flex-direction: column; + height: calc(100vh - 5rem); + } + + &__preview { + box-sizing: border-box; + display: flex; + flex-direction: column; + align-items: center; + height: 360px; + width: 55%; + + margin-right: 1.5rem; + + @include isMobile { + max-width: unset; + margin-right: unset; + + width: 100%; + height: unset; + flex-grow: 1; + } + + &__filename { + & > input { + margin-top: 1rem; + } + } + + &__canvas { + box-sizing: border-box; + width: 100%; + height: 100%; + display: flex; + flex-grow: 1; + justify-content: center; + align-items: center; + + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==") + left center; + + border: 1px solid var(--ImageExportModal-preview-border); + border-radius: 12px; + + overflow: hidden; + padding: 1rem; + + & > canvas { + max-width: calc(100% - 2rem); + max-height: calc(100% - 2rem); + + filter: none !important; + + @include isMobile { + max-height: 100%; + } + } + + @include isMobile { + margin-top: 24px; + max-width: unset; + } + } + } + + &__settings { + display: flex; + flex-direction: column; + flex-wrap: wrap; + gap: 18px; + + @include isMobile { + margin-left: unset; + margin-top: 1rem; + flex-direction: row; + gap: 6px 34px; + + align-content: flex-start; + } + + &__setting { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + @include isMobile { + flex-direction: column; + align-items: start; + justify-content: unset; + height: 52px; + } + + &__label { + display: flex; + flex-direction: row; + align-items: center; + + font-family: "Assistant"; + font-weight: 600; + font-size: 1rem; + line-height: 150%; + + & svg { + width: 20px; + height: 20px; + margin-left: 10px; + } + } + + &__content { + display: flex; + height: 100%; + align-items: center; + } + } + + &__buttons { + flex-grow: 1; + flex-wrap: wrap; + display: flex; + flex-direction: row; + gap: 11px; + + align-items: flex-end; + align-content: flex-end; + + @include isMobile { + padding-top: 32px; + flex-basis: 100%; + justify-content: center; + } + + &__button { + box-sizing: border-box; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 8px 16px; + flex-shrink: 0; + width: fit-content; + gap: 8px; + + height: 40px; + border: 0; + border-radius: 8px; + + user-select: none; + font-family: "Assistant"; + font-style: normal; + font-weight: 600; + font-size: 0.75rem; + line-height: 100%; + transition: 150ms ease-out; + transition-property: background, color; + + background: var(--color-primary); + color: var(--color-icon-white); + + &:hover { + background: var(--color-primary-darker); + color: var(--color-icon-white); + } + + &:active { + background: var(--color-primary-darkest); + } + + & > svg { + width: 20px; + height: 20px; + } + } + } + } + } +} diff --git a/src/components/ImageExportDialog.tsx b/src/components/ImageExportDialog.tsx index 38467d6eb..604f50b4f 100644 --- a/src/components/ImageExportDialog.tsx +++ b/src/components/ImageExportDialog.tsx @@ -1,25 +1,39 @@ import React, { useEffect, useRef, useState } from "react"; + +import type { ActionManager } from "../actions/manager"; +import type { AppClassProperties, BinaryFiles, UIAppState } from "../types"; + +import { + actionExportWithDarkMode, + actionChangeExportBackground, + actionChangeExportEmbedScene, + actionChangeExportScale, + actionChangeProjectName, +} from "../actions/actionExport"; import { probablySupportsClipboardBlob } from "../clipboard"; -import { canvasToBlob } from "../data/blob"; -import { NonDeletedExcalidrawElement } from "../element/types"; -import { t } from "../i18n"; -import { getSelectedElements, isSomeElementSelected } from "../scene"; -import { AppClassProperties, BinaryFiles, UIAppState } from "../types"; -import { Dialog } from "./Dialog"; -import { clipboard } from "./icons"; -import Stack from "./Stack"; -import OpenColor from "open-color"; -import { CheckboxItem } from "./CheckboxItem"; import { DEFAULT_EXPORT_PADDING, EXPORT_IMAGE_TYPES, isFirefox, + EXPORT_SCALES, } from "../constants"; + +import { canvasToBlob } from "../data/blob"; import { nativeFileSystemSupported } from "../data/filesystem"; -import { ActionManager } from "../actions/manager"; +import { NonDeletedExcalidrawElement } from "../element/types"; +import { t } from "../i18n"; +import { getSelectedElements, isSomeElementSelected } from "../scene"; import { exportToCanvas } from "../packages/utils"; -import "./ExportDialog.scss"; +import { copyIcon, downloadIcon, helpIcon } from "./icons"; +import { Button } from "./Button"; +import { Dialog } from "./Dialog"; +import { RadioGroup } from "./RadioGroup"; +import { Switch } from "./Switch"; +import { Tooltip } from "./Tooltip"; + +import "./ImageExportDialog.scss"; +import { useAppProps } from "./App"; const supportsContextFilters = "filter" in document.createElement("canvas").getContext("2d")!; @@ -36,50 +50,36 @@ export const ErrorCanvasPreview = () => { ); }; -export type ExportCB = ( - elements: readonly NonDeletedExcalidrawElement[], - scale?: number, -) => void; - -const ExportButton: React.FC<{ - color: keyof OpenColor; - onClick: () => void; - title: string; - shade?: number; - children?: React.ReactNode; -}> = ({ children, title, onClick, color, shade = 6 }) => { - return ( - - ); -}; - -const ImageExportModal = ({ - elements, - appState, - files, - actionManager, - onExportImage, -}: { +type ImageExportModalProps = { appState: UIAppState; elements: readonly NonDeletedExcalidrawElement[]; files: BinaryFiles; actionManager: ActionManager; onExportImage: AppClassProperties["onExportImage"]; -}) => { +}; + +const ImageExportModal = ({ + appState, + elements, + files, + actionManager, + onExportImage, +}: ImageExportModalProps) => { + const appProps = useAppProps(); + const [projectName, setProjectName] = useState(appState.name); + const someElementIsSelected = isSomeElementSelected(elements, appState); + const [exportSelected, setExportSelected] = useState(someElementIsSelected); + const [exportWithBackground, setExportWithBackground] = useState( + appState.exportBackground, + ); + const [exportDarkMode, setExportDarkMode] = useState( + appState.exportWithDarkMode, + ); + const [embedScene, setEmbedScene] = useState(appState.exportEmbedScene); + const [exportScale, setExportScale] = useState(appState.exportScale); + const previewRef = useRef(null); const [renderError, setRenderError] = useState(null); @@ -93,6 +93,7 @@ const ImageExportModal = ({ return; } const maxWidth = previewNode.offsetWidth; + const maxHeight = previewNode.offsetHeight; if (!maxWidth) { return; } @@ -101,7 +102,7 @@ const ImageExportModal = ({ appState, files, exportPadding: DEFAULT_EXPORT_PADDING, - maxWidthOrHeight: maxWidth, + maxWidthOrHeight: Math.max(maxWidth, maxHeight), }) .then((canvas) => { setRenderError(null); @@ -118,89 +119,190 @@ const ImageExportModal = ({ }, [appState, files, exportedElements]); return ( -
-
- {renderError && } -
- {supportsContextFilters && - actionManager.renderAction("exportWithDarkMode")} -
-
- {actionManager.renderAction("changeExportBackground")} - {someElementIsSelected && ( - setExportSelected(checked)} - > - {t("labels.onlySelected")} - +
+

{t("imageExportDialog.header")}

+
+
+ {renderError && } +
+
+ {!nativeFileSystemSupported && ( + { + setProjectName(event.target.value); + actionManager.executeAction( + actionChangeProjectName, + "ui", + event.target.value, + ); + }} + /> )} - {actionManager.renderAction("changeExportEmbedScene")}
-
- - {actionManager.renderAction("changeExportScale")} - -

- {t("buttons.scale")} -

-
-
- {!nativeFileSystemSupported && - actionManager.renderAction("changeProjectName")} -
- - - onExportImage(EXPORT_IMAGE_TYPES.png, exportedElements) - } - > - PNG - - - onExportImage(EXPORT_IMAGE_TYPES.svg, exportedElements) - } - > - SVG - - {/* firefox supports clipboard API under a flag, - so let's throw and tell people what they can do */} - {(probablySupportsClipboardBlob || isFirefox) && ( - - onExportImage(EXPORT_IMAGE_TYPES.clipboard, exportedElements) - } - color="gray" - shade={7} +
+

{t("imageExportDialog.header")}

+ {someElementIsSelected && ( + - {clipboard} - + { + setExportSelected(checked); + }} + /> + )} - + + { + setExportWithBackground(checked); + actionManager.executeAction( + actionChangeExportBackground, + "ui", + checked, + ); + }} + /> + + {supportsContextFilters && ( + + { + setExportDarkMode(checked); + actionManager.executeAction( + actionExportWithDarkMode, + "ui", + checked, + ); + }} + /> + + )} + + { + setEmbedScene(checked); + actionManager.executeAction( + actionChangeExportEmbedScene, + "ui", + checked, + ); + }} + /> + + + { + setExportScale(scale); + actionManager.executeAction(actionChangeExportScale, "ui", scale); + }} + choices={EXPORT_SCALES.map((scale) => ({ + value: scale, + label: `${scale}\u00d7`, + }))} + /> + + +
+ + + {(probablySupportsClipboardBlob || isFirefox) && ( + + )} +
+
+
+ ); +}; + +type ExportSettingProps = { + label: string; + children: React.ReactNode; + tooltip?: string; + name?: string; +}; + +const ExportSetting = ({ + label, + children, + tooltip, + name, +}: ExportSettingProps) => { + return ( +
+ +
+ {children} +
); }; @@ -225,7 +327,7 @@ export const ImageExportDialog = ({ } return ( - + setPublishLibSuccess(null)} title={t("publishSuccessDialog.title")} className="publish-library-success" - small={true} + size="small" >

+ />
void; label: string; isNameEditable: boolean; + ignoreFocus?: boolean; }; export const ProjectName = (props: Props) => { @@ -19,7 +20,9 @@ export const ProjectName = (props: Props) => { const [fileName, setFileName] = useState(props.value); const handleBlur = (event: any) => { - focusNearestParent(event.target); + if (!props.ignoreFocus) { + focusNearestParent(event.target); + } const value = event.target.value; if (value !== props.value) { props.onChange(value); diff --git a/src/components/RadioGroup.scss b/src/components/RadioGroup.scss new file mode 100644 index 000000000..860648269 --- /dev/null +++ b/src/components/RadioGroup.scss @@ -0,0 +1,100 @@ +@import "../css/variables.module"; + +.excalidraw { + --RadioGroup-background: #ffffff; + --RadioGroup-border: var(--color-gray-30); + + --RadioGroup-choice-color-off: var(--color-primary); + --RadioGroup-choice-color-off-hover: var(--color-primary-darkest); + --RadioGroup-choice-background-off: white; + --RadioGroup-choice-background-off-active: var(--color-gray-20); + + --RadioGroup-choice-color-on: white; + --RadioGroup-choice-background-on: var(--color-primary); + --RadioGroup-choice-background-on-hover: var(--color-primary-darker); + --RadioGroup-choice-background-on-active: var(--color-primary-darkest); + + &.theme--dark { + --RadioGroup-background: var(--color-gray-85); + --RadioGroup-border: var(--color-gray-70); + + --RadioGroup-choice-background-off: var(--color-gray-85); + --RadioGroup-choice-background-off-active: var(--color-gray-70); + --RadioGroup-choice-color-on: var(--color-gray-85); + } + + .RadioGroup { + box-sizing: border-box; + display: flex; + flex-direction: row; + align-items: flex-start; + + padding: 3px; + border-radius: 10px; + + background: var(--RadioGroup-background); + border: 1px solid var(--RadioGroup-border); + + &__choice { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 24px; + + color: var(--RadioGroup-choice-color-off); + background: var(--RadioGroup-choice-background-off); + + border-radius: 8px; + + font-family: "Assistant"; + font-style: normal; + font-weight: 600; + font-size: 0.75rem; + line-height: 100%; + user-select: none; + letter-spacing: 0.4px; + + transition: all 75ms ease-out; + + &:hover { + color: var(--RadioGroup-choice-color-off-hover); + } + + &:active { + background: var(--RadioGroup-choice-background-off-active); + } + + &.active { + color: var(--RadioGroup-choice-color-on); + background: var(--RadioGroup-choice-background-on); + + &:hover { + background: var(--RadioGroup-choice-background-on-hover); + } + + &:active { + background: var(--RadioGroup-choice-background-on-active); + } + } + + & input { + z-index: 1; + position: absolute; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + + border-radius: 8px; + + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + + cursor: pointer; + } + } + } +} diff --git a/src/components/RadioGroup.tsx b/src/components/RadioGroup.tsx new file mode 100644 index 000000000..40c6551f1 --- /dev/null +++ b/src/components/RadioGroup.tsx @@ -0,0 +1,42 @@ +import clsx from "clsx"; +import "./RadioGroup.scss"; + +export type RadioGroupChoice = { + value: T; + label: string; +}; + +export type RadioGroupProps = { + choices: RadioGroupChoice[]; + value: T; + onChange: (value: T) => void; + name: string; +}; + +export const RadioGroup = function ({ + onChange, + value, + choices, + name, +}: RadioGroupProps) { + return ( +
+ {choices.map((choice) => ( +
+ onChange(choice.value)} + /> + {choice.label} +
+ ))} +
+ ); +}; diff --git a/src/components/Switch.scss b/src/components/Switch.scss new file mode 100644 index 000000000..ab98bad63 --- /dev/null +++ b/src/components/Switch.scss @@ -0,0 +1,116 @@ +@import "../css/variables.module"; + +.excalidraw { + --Switch-disabled-color: #d6d6d6; + --Switch-track-background: white; + --Switch-thumb-background: #3d3d3d; + + &.theme--dark { + --Switch-disabled-color: #5c5c5c; + --Switch-track-background: #242424; + --Switch-thumb-background: #b8b8b8; + } + + .Switch { + position: relative; + box-sizing: border-box; + + width: 40px; + height: 20px; + border-radius: 12px; + + transition-property: background, border; + transition-duration: 150ms; + transition-timing-function: ease-out; + + background: var(--Switch-track-background); + border: 1px solid var(--Switch-disabled-color); + + &:hover { + background: var(--Switch-track-background); + border: 1px solid #999999; + } + + &.toggled { + background: var(--color-primary); + border: 1px solid var(--color-primary); + + &:hover { + background: var(--color-primary-darker); + border: 1px solid var(--color-primary-darker); + } + } + + &.disabled { + background: var(--Switch-track-background); + border: 1px solid var(--Switch-disabled-color); + + &.toggled { + background: var(--Switch-disabled-color); + border: 1px solid var(--Switch-disabled-color); + } + } + + &:before { + content: ""; + box-sizing: border-box; + display: block; + pointer-events: none; + position: absolute; + + border-radius: 100%; + transition: all 150ms ease-out; + + width: 10px; + height: 10px; + top: 4px; + left: 4px; + + background: var(--Switch-thumb-background); + } + + &:active:before { + width: 12px; + } + + &.toggled:before { + width: 14px; + height: 14px; + left: 22px; + top: 2px; + + background: var(--Switch-track-background); + } + + &.toggled:active:before { + width: 16px; + left: 20px; + } + + &.disabled:before { + background: var(--Switch-disabled-color); + } + + &.disabled.toggled:before { + background: var(--color-gray-50); + } + + & input { + width: 100%; + height: 100%; + margin: 0; + + border-radius: 12px; + + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + + cursor: pointer; + + &:disabled { + cursor: unset; + } + } + } +} diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx new file mode 100644 index 000000000..dfbf332fc --- /dev/null +++ b/src/components/Switch.tsx @@ -0,0 +1,38 @@ +import clsx from "clsx"; + +import "./Switch.scss"; + +export type SwitchProps = { + name: string; + checked: boolean; + title?: string; + onChange: (value: boolean) => void; + disabled?: boolean; +}; + +export const Switch = ({ + title, + name, + checked, + onChange, + disabled = false, +}: SwitchProps) => { + return ( +
+ onChange(!checked)} + onKeyDown={(e) => { + if (e.key === " ") { + onChange(!checked); + } + }} + /> +
+ ); +}; diff --git a/src/components/icons.tsx b/src/components/icons.tsx index 784e81024..3841d030e 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -1550,3 +1550,32 @@ export const handIcon = createIcon( , tablerIconProps, ); + +export const downloadIcon = createIcon( + <> + + + + + , + tablerIconProps, +); + +export const copyIcon = createIcon( + <> + + + + , + tablerIconProps, +); + +export const helpIcon = createIcon( + <> + + + + + , + tablerIconProps, +); diff --git a/src/excalidraw-app/collab/RoomDialog.tsx b/src/excalidraw-app/collab/RoomDialog.tsx index 4810b5a55..05772774a 100644 --- a/src/excalidraw-app/collab/RoomDialog.tsx +++ b/src/excalidraw-app/collab/RoomDialog.tsx @@ -180,7 +180,7 @@ const RoomDialog = ({ }; return ( ", () => { toggleMenu(container); fireEvent.click(queryByTestId(container, "image-export-button")!); const textInput: HTMLInputElement | null = document.querySelector( - ".ExportDialog .ProjectName .TextInput", + ".ImageExportModal .ImageExportModal__preview__filename .TextInput", ); expect(textInput?.value).toContain(`${t("labels.untitled")}`); expect(textInput?.nodeName).toBe("INPUT"); @@ -303,10 +303,11 @@ describe("", () => { toggleMenu(container); await fireEvent.click(queryByTestId(container, "image-export-button")!); const textInput = document.querySelector( - ".ExportDialog .ProjectName .TextInput--readonly", - ); - expect(textInput?.textContent).toEqual(name); - expect(textInput?.nodeName).toBe("SPAN"); + ".ImageExportModal .ImageExportModal__preview__filename .TextInput", + ) as HTMLInputElement; + expect(textInput?.value).toEqual(name); + expect(textInput?.nodeName).toBe("INPUT"); + expect(textInput?.disabled).toBe(true); }); }); From a91e401554388b72741efc19b27478f7964d939a Mon Sep 17 00:00:00 2001 From: Arnost Pleskot Date: Mon, 29 May 2023 16:01:44 +0200 Subject: [PATCH 083/451] feat: clearing library cache (#6621) Co-authored-by: dwelle --- src/components/App.tsx | 1 + src/components/LibraryMenuHeaderContent.tsx | 63 +++++++++++---------- src/components/LibraryMenuItems.tsx | 4 ++ src/components/LibraryMenuSection.tsx | 9 ++- src/components/LibraryUnit.tsx | 6 +- src/data/library.ts | 15 +++++ src/hooks/useLibraryItemSvg.ts | 29 ++++++++-- 7 files changed, 86 insertions(+), 41 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 49919c957..0b730fc47 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1072,6 +1072,7 @@ class App extends React.Component { this.unmounted = true; this.removeEventListeners(); this.scene.destroy(); + this.library.destroy(); clearTimeout(touchTimeout); touchTimeout = 0; } diff --git a/src/components/LibraryMenuHeaderContent.tsx b/src/components/LibraryMenuHeaderContent.tsx index d51f651f3..56c8fe6d0 100644 --- a/src/components/LibraryMenuHeaderContent.tsx +++ b/src/components/LibraryMenuHeaderContent.tsx @@ -24,6 +24,7 @@ import DropdownMenu from "./dropdownMenu/DropdownMenu"; import { isLibraryMenuOpenAtom } from "./LibraryMenu"; import { useUIAppState } from "../context/ui-appState"; import clsx from "clsx"; +import { useLibraryCache } from "../hooks/useLibraryItemSvg"; const getSelectedItems = ( libraryItems: LibraryItems, @@ -55,7 +56,7 @@ export const LibraryDropdownMenuButton: React.FC<{ jotaiScope, ); - const renderRemoveLibAlert = useCallback(() => { + const renderRemoveLibAlert = () => { const content = selectedItems.length ? t("alerts.removeItemsFromsLibrary", { count: selectedItems.length }) : t("alerts.resetLibrary"); @@ -80,7 +81,7 @@ export const LibraryDropdownMenuButton: React.FC<{

{content}

); - }, [selectedItems, onRemoveFromLibrary, resetLibrary]); + }; const [showRemoveLibAlert, setShowRemoveLibAlert] = useState(false); @@ -136,20 +137,20 @@ export const LibraryDropdownMenuButton: React.FC<{ ); }, [setPublishLibSuccess, publishLibSuccess]); - const onPublishLibSuccess = useCallback( - (data: { url: string; authorName: string }, libraryItems: LibraryItems) => { - setShowPublishLibraryDialog(false); - setPublishLibSuccess({ url: data.url, authorName: data.authorName }); - const nextLibItems = libraryItems.slice(); - nextLibItems.forEach((libItem) => { - if (selectedItems.includes(libItem.id)) { - libItem.status = "published"; - } - }); - library.setLibrary(nextLibItems); - }, - [setShowPublishLibraryDialog, setPublishLibSuccess, selectedItems, library], - ); + const onPublishLibSuccess = ( + data: { url: string; authorName: string }, + libraryItems: LibraryItems, + ) => { + setShowPublishLibraryDialog(false); + setPublishLibSuccess({ url: data.url, authorName: data.authorName }); + const nextLibItems = libraryItems.slice(); + nextLibItems.forEach((libItem) => { + if (selectedItems.includes(libItem.id)) { + libItem.status = "published"; + } + }); + library.setLibrary(nextLibItems); + }; const onLibraryImport = async () => { try { @@ -280,27 +281,29 @@ export const LibraryDropdownMenu = ({ className?: string; }) => { const { library } = useApp(); + const { clearLibraryCache, deleteItemsFromLibraryCache } = useLibraryCache(); const appState = useUIAppState(); const setAppState = useExcalidrawSetAppState(); const [libraryItemsData] = useAtom(libraryItemsAtom, jotaiScope); - const removeFromLibrary = useCallback( - async (libraryItems: LibraryItems) => { - const nextItems = libraryItems.filter( - (item) => !selectedItems.includes(item.id), - ); - library.setLibrary(nextItems).catch(() => { - setAppState({ errorMessage: t("alerts.errorRemovingFromLibrary") }); - }); - onSelectItems([]); - }, - [library, setAppState, selectedItems, onSelectItems], - ); + const removeFromLibrary = async (libraryItems: LibraryItems) => { + const nextItems = libraryItems.filter( + (item) => !selectedItems.includes(item.id), + ); + library.setLibrary(nextItems).catch(() => { + setAppState({ errorMessage: t("alerts.errorRemovingFromLibrary") }); + }); - const resetLibrary = useCallback(() => { + deleteItemsFromLibraryCache(selectedItems); + + onSelectItems([]); + }; + + const resetLibrary = () => { library.resetLibrary(); - }, [library]); + clearLibraryCache(); + }; return ( ([]); + const { svgCache } = useLibraryCache(); const unpublishedItems = libraryItems.filter( (item) => item.status !== "published", @@ -224,6 +226,7 @@ export default function LibraryMenuItems({ onItemDrag={onItemDrag} onClick={onItemClick} isItemSelected={isItemSelected} + svgCache={svgCache} /> )} @@ -243,6 +246,7 @@ export default function LibraryMenuItems({ onItemDrag={onItemDrag} onClick={onItemClick} isItemSelected={isItemSelected} + svgCache={svgCache} /> ) : unpublishedItems.length > 0 ? (
void; onItemDrag: (id: LibraryItem["id"], event: React.DragEvent) => void; isItemSelected: (id: LibraryItem["id"] | null) => boolean; + svgCache: SvgCache; } function LibraryRow({ @@ -34,6 +34,7 @@ function LibraryRow({ onItemDrag, isItemSelected, onClick, + svgCache, }: Props) { return ( @@ -47,6 +48,7 @@ function LibraryRow({ selected={isItemSelected(item.id)} onToggle={onItemSelectToggle} onDrag={onItemDrag} + svgCache={svgCache} /> ))} @@ -68,11 +70,11 @@ function LibraryMenuSection({ onItemDrag, isItemSelected, onClick, + svgCache, }: Props) { const rows = Math.ceil(items.length / ITEMS_PER_ROW); const [, startTransition] = useTransition(); const [index, setIndex] = useState(0); - const [svgCache] = useAtom(libraryItemSvgsCache); const rowsRenderedPerBatch = useMemo(() => { return svgCache.size === 0 @@ -99,6 +101,7 @@ function LibraryMenuSection({ onItemDrag={onItemDrag} onClick={onClick} isItemSelected={isItemSelected} + svgCache={svgCache} /> ) : ( diff --git a/src/components/LibraryUnit.tsx b/src/components/LibraryUnit.tsx index 68fdec143..97f73f80a 100644 --- a/src/components/LibraryUnit.tsx +++ b/src/components/LibraryUnit.tsx @@ -5,7 +5,7 @@ import { LibraryItem } from "../types"; import "./LibraryUnit.scss"; import { CheckboxItem } from "./CheckboxItem"; import { PlusIcon } from "./icons"; -import { useLibraryItemSvg } from "../hooks/useLibraryItemSvg"; +import { SvgCache, useLibraryItemSvg } from "../hooks/useLibraryItemSvg"; export const LibraryUnit = ({ id, @@ -15,6 +15,7 @@ export const LibraryUnit = ({ selected, onToggle, onDrag, + svgCache, }: { id: LibraryItem["id"] | /** for pending item */ null; elements?: LibraryItem["elements"]; @@ -23,9 +24,10 @@ export const LibraryUnit = ({ selected: boolean; onToggle: (id: string, event: React.MouseEvent) => void; onDrag: (id: string, event: React.DragEvent) => void; + svgCache: SvgCache; }) => { const ref = useRef(null); - const svg = useLibraryItemSvg(id, elements); + const svg = useLibraryItemSvg(id, elements, svgCache); useEffect(() => { const node = ref.current; diff --git a/src/data/library.ts b/src/data/library.ts index b9033bace..381caed11 100644 --- a/src/data/library.ts +++ b/src/data/library.ts @@ -22,6 +22,7 @@ import { DEFAULT_SIDEBAR, LIBRARY_SIDEBAR_TAB, } from "../constants"; +import { libraryItemSvgsCache } from "../hooks/useLibraryItemSvg"; export const libraryItemsAtom = atom<{ status: "loading" | "loaded"; @@ -115,6 +116,20 @@ class Library { } }; + /** call on excalidraw instance unmount */ + destroy = () => { + this.isInitialized = false; + this.updateQueue = []; + this.lastLibraryItems = []; + jotaiStore.set(libraryItemSvgsCache, new Map()); + // TODO uncomment after/if we make jotai store scoped to each excal instance + // jotaiStore.set(libraryItemsAtom, { + // status: "loading", + // isInitialized: false, + // libraryItems: [], + // }); + }; + resetLibrary = () => { return this.setLibrary([]); }; diff --git a/src/hooks/useLibraryItemSvg.ts b/src/hooks/useLibraryItemSvg.ts index d0a0f5326..ba9802199 100644 --- a/src/hooks/useLibraryItemSvg.ts +++ b/src/hooks/useLibraryItemSvg.ts @@ -1,12 +1,13 @@ import { atom, useAtom } from "jotai"; import { useEffect, useState } from "react"; import { COLOR_PALETTE } from "../colors"; +import { jotaiScope } from "../jotai"; import { exportToSvg } from "../packages/utils"; import { LibraryItem } from "../types"; -export const libraryItemSvgsCache = atom>( - new Map(), -); +export type SvgCache = Map; + +export const libraryItemSvgsCache = atom(new Map()); const exportLibraryItemToSvg = async (elements: LibraryItem["elements"]) => { return await exportToSvg({ @@ -22,8 +23,8 @@ const exportLibraryItemToSvg = async (elements: LibraryItem["elements"]) => { export const useLibraryItemSvg = ( id: LibraryItem["id"] | null, elements: LibraryItem["elements"] | undefined, + svgCache: SvgCache, ): SVGSVGElement | undefined => { - const [svgCache, setSvgCache] = useAtom(libraryItemSvgsCache); const [svg, setSvg] = useState(); useEffect(() => { @@ -40,7 +41,7 @@ export const useLibraryItemSvg = ( const exportedSvg = await exportLibraryItemToSvg(elements); if (exportedSvg) { - setSvgCache(svgCache.set(id, exportedSvg)); + svgCache.set(id, exportedSvg); setSvg(exportedSvg); } })(); @@ -53,7 +54,23 @@ export const useLibraryItemSvg = ( })(); } } - }, [id, elements, svgCache, setSvgCache, setSvg]); + }, [id, elements, svgCache, setSvg]); return svg; }; + +export const useLibraryCache = () => { + const [svgCache] = useAtom(libraryItemSvgsCache, jotaiScope); + + const clearLibraryCache = () => svgCache.clear(); + + const deleteItemsFromLibraryCache = (items: LibraryItem["id"][]) => { + items.forEach((item) => svgCache.delete(item)); + }; + + return { + clearLibraryCache, + deleteItemsFromLibraryCache, + svgCache, + }; +}; From 1e3c94a37ad80cb8d32dc339758eefc54ae5f108 Mon Sep 17 00:00:00 2001 From: Arnost Pleskot Date: Wed, 31 May 2023 10:22:02 +0200 Subject: [PATCH 084/451] feat: recover scrolled position after Library re-opening (#6624) Co-authored-by: dwelle --- src/components/LibraryMenuItems.tsx | 13 +++- src/components/LibraryMenuSection.tsx | 8 ++- src/components/LibraryUnit.scss | 35 +++++++++++ src/components/LibraryUnit.tsx | 1 + src/components/Stack.tsx | 89 +++++++++++++-------------- src/hooks/useScrollPosition.ts | 32 ++++++++++ 6 files changed, 129 insertions(+), 49 deletions(-) create mode 100644 src/hooks/useScrollPosition.ts diff --git a/src/components/LibraryMenuItems.tsx b/src/components/LibraryMenuItems.tsx index 55de2aaf6..8dd6b30f2 100644 --- a/src/components/LibraryMenuItems.tsx +++ b/src/components/LibraryMenuItems.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { serializeLibraryAsJSON } from "../data/json"; import { t } from "../i18n"; import { @@ -15,6 +15,7 @@ import { duplicateElements } from "../element/newElement"; import { LibraryMenuControlButtons } from "./LibraryMenuControlButtons"; import { LibraryDropdownMenu } from "./LibraryMenuHeaderContent"; import LibraryMenuSection from "./LibraryMenuSection"; +import { useScrollPosition } from "../hooks/useScrollPosition"; import { useLibraryCache } from "../hooks/useLibraryItemSvg"; import "./LibraryMenuItems.scss"; @@ -39,6 +40,15 @@ export default function LibraryMenuItems({ id: string; }) { const [selectedItems, setSelectedItems] = useState([]); + const libraryContainerRef = useRef(null); + const scrollPosition = useScrollPosition(libraryContainerRef); + + // This effect has to be called only on first render, therefore `scrollPosition` isn't in the dependency array + useEffect(() => { + if (scrollPosition > 0) { + libraryContainerRef.current?.scrollTo(0, scrollPosition); + } + }, []); // eslint-disable-line react-hooks/exhaustive-deps const { svgCache } = useLibraryCache(); const unpublishedItems = libraryItems.filter( @@ -183,6 +193,7 @@ export default function LibraryMenuItems({ flex: publishedItems.length > 0 ? 1 : "0 1 auto", marginBottom: 0, }} + ref={libraryContainerRef} > <> {!isLibraryEmpty && ( diff --git a/src/components/LibraryMenuSection.tsx b/src/components/LibraryMenuSection.tsx index d13c8959d..496f045b7 100644 --- a/src/components/LibraryMenuSection.tsx +++ b/src/components/LibraryMenuSection.tsx @@ -58,9 +58,11 @@ function LibraryRow({ const EmptyLibraryRow = () => ( - -
- + {Array.from({ length: ITEMS_PER_ROW }).map((_, index) => ( + +
+ + ))} ); diff --git a/src/components/LibraryUnit.scss b/src/components/LibraryUnit.scss index 85d7505c3..1bfc1e6df 100644 --- a/src/components/LibraryUnit.scss +++ b/src/components/LibraryUnit.scss @@ -20,6 +20,27 @@ border-color: var(--color-primary); border-width: 1px; } + + &--skeleton { + opacity: 0.5; + background: linear-gradient( + -45deg, + var(--color-gray-10), + var(--color-gray-20), + var(--color-gray-10) + ); + background-size: 200% 200%; + animation: library-unit__skeleton-opacity-animation 0.3s linear; + } + } + + &.theme--dark .library-unit--skeleton { + background-image: linear-gradient( + -45deg, + var(--color-gray-100), + var(--color-gray-80), + var(--color-gray-100) + ); } .library-unit__dragger { @@ -142,4 +163,18 @@ transform: scale(0.85); } } + + @keyframes library-unit__skeleton-opacity-animation { + 0% { + opacity: 0; + } + + 75% { + opacity: 0; + } + + 100% { + opacity: 0.5; + } + } } diff --git a/src/components/LibraryUnit.tsx b/src/components/LibraryUnit.tsx index 97f73f80a..f256b49f1 100644 --- a/src/components/LibraryUnit.tsx +++ b/src/components/LibraryUnit.tsx @@ -58,6 +58,7 @@ export const LibraryUnit = ({ "library-unit__active": elements, "library-unit--hover": elements && isHovered, "library-unit--selected": selected, + "library-unit--skeleton": !svg, })} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} diff --git a/src/components/Stack.tsx b/src/components/Stack.tsx index aa18e8998..c54a6aef8 100644 --- a/src/components/Stack.tsx +++ b/src/components/Stack.tsx @@ -1,6 +1,6 @@ import "./Stack.scss"; -import React from "react"; +import React, { forwardRef } from "react"; import clsx from "clsx"; type StackProps = { @@ -10,53 +10,52 @@ type StackProps = { justifyContent?: "center" | "space-around" | "space-between"; className?: string | boolean; style?: React.CSSProperties; + ref: React.RefObject; }; -const RowStack = ({ - children, - gap, - align, - justifyContent, - className, - style, -}: StackProps) => { - return ( -
- {children} -
- ); -}; +const RowStack = forwardRef( + ( + { children, gap, align, justifyContent, className, style }: StackProps, + ref: React.ForwardedRef, + ) => { + return ( +
+ {children} +
+ ); + }, +); -const ColStack = ({ - children, - gap, - align, - justifyContent, - className, - style, -}: StackProps) => { - return ( -
- {children} -
- ); -}; +const ColStack = forwardRef( + ( + { children, gap, align, justifyContent, className, style }: StackProps, + ref: React.ForwardedRef, + ) => { + return ( +
+ {children} +
+ ); + }, +); export default { Row: RowStack, diff --git a/src/hooks/useScrollPosition.ts b/src/hooks/useScrollPosition.ts new file mode 100644 index 000000000..e4efb460e --- /dev/null +++ b/src/hooks/useScrollPosition.ts @@ -0,0 +1,32 @@ +import { useEffect } from "react"; +import { atom, useAtom } from "jotai"; +import throttle from "lodash.throttle"; + +const scrollPositionAtom = atom(0); + +export const useScrollPosition = ( + elementRef: React.RefObject, +) => { + const [scrollPosition, setScrollPosition] = useAtom(scrollPositionAtom); + + useEffect(() => { + const { current: element } = elementRef; + if (!element) { + return; + } + + const handleScroll = throttle(() => { + const { scrollTop } = element; + setScrollPosition(scrollTop); + }, 200); + + element.addEventListener("scroll", handleScroll); + + return () => { + handleScroll.cancel(); + element.removeEventListener("scroll", handleScroll); + }; + }, [elementRef, setScrollPosition]); + + return scrollPosition; +}; From 82d8d02697e534bcfbeffe7f9438ca60c72230d9 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Wed, 31 May 2023 17:30:14 +0530 Subject: [PATCH 085/451] test: Add coverage script (#6634) Add coverage script --- package.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/package.json b/package.json index 4556cb5f7..246c785a5 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,15 @@ }, "homepage": ".", "jest": { + "collectCoverageFrom": [ + "src/**/*.{js,jsx,ts,tsx}" + ], + "coveragePathIgnorePatterns": [ + "/locales", + "/src/packages/excalidraw/dist/", + "/src/packages/excalidraw/types", + "/src/packages/excalidraw/example" + ], "transformIgnorePatterns": [ "node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access)/)" ], @@ -128,6 +137,7 @@ "test:typecheck": "tsc", "test:update": "yarn test:app --updateSnapshot --watchAll=false", "test": "yarn test:app", + "test:coverage": "react-scripts test --passWithNoTests --coverage --watchAll", "autorelease": "node scripts/autorelease.js", "prerelease": "node scripts/prerelease.js", "release": "node scripts/release.js" From 253c5c78663314d6cb2c1d6d03a0139eddddaff9 Mon Sep 17 00:00:00 2001 From: Arnost Pleskot Date: Wed, 31 May 2023 15:37:13 +0200 Subject: [PATCH 086/451] perf: memoize rendering of library (#6622) Co-authored-by: dwelle --- src/components/LibraryMenu.tsx | 129 ++++++++++----- src/components/LibraryMenuItems.scss | 6 + src/components/LibraryMenuItems.tsx | 229 ++++++++++++++++---------- src/components/LibraryMenuSection.tsx | 145 ++++++---------- src/components/LibraryUnit.scss | 2 +- src/components/LibraryUnit.tsx | 171 +++++++++---------- src/hooks/useLibraryItemSvg.ts | 1 + 7 files changed, 377 insertions(+), 306 deletions(-) diff --git a/src/components/LibraryMenu.tsx b/src/components/LibraryMenu.tsx index a49f31970..f5f386d4c 100644 --- a/src/components/LibraryMenu.tsx +++ b/src/components/LibraryMenu.tsx @@ -1,4 +1,4 @@ -import React, { useCallback } from "react"; +import React, { useState, useCallback, useMemo, useRef } from "react"; import Library, { distributeLibraryItemsOnSquareGrid, libraryItemsAtom, @@ -27,6 +27,8 @@ import { useUIAppState } from "../context/ui-appState"; import "./LibraryMenu.scss"; import { LibraryMenuControlButtons } from "./LibraryMenuControlButtons"; +import { isShallowEqual } from "../utils"; +import { NonDeletedExcalidrawElement } from "../element/types"; export const isLibraryMenuOpenAtom = atom(false); @@ -42,7 +44,9 @@ export const LibraryMenuContent = ({ libraryReturnUrl, library, id, - appState, + theme, + selectedItems, + onSelectItems, }: { pendingElements: LibraryItem["elements"]; onInsertLibraryItems: (libraryItems: LibraryItems) => void; @@ -51,33 +55,47 @@ export const LibraryMenuContent = ({ libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"]; library: Library; id: string; - appState: UIAppState; + theme: UIAppState["theme"]; + selectedItems: LibraryItem["id"][]; + onSelectItems: (id: LibraryItem["id"][]) => void; }) => { const [libraryItemsData] = useAtom(libraryItemsAtom, jotaiScope); - const addToLibrary = useCallback( - async (elements: LibraryItem["elements"], libraryItems: LibraryItems) => { - trackEvent("element", "addToLibrary", "ui"); - if (elements.some((element) => element.type === "image")) { - return setAppState({ - errorMessage: "Support for adding images to the library coming soon!", + const _onAddToLibrary = useCallback( + (elements: LibraryItem["elements"]) => { + const addToLibrary = async ( + processedElements: LibraryItem["elements"], + libraryItems: LibraryItems, + ) => { + trackEvent("element", "addToLibrary", "ui"); + if (processedElements.some((element) => element.type === "image")) { + return setAppState({ + errorMessage: + "Support for adding images to the library coming soon!", + }); + } + const nextItems: LibraryItems = [ + { + status: "unpublished", + elements: processedElements, + id: randomId(), + created: Date.now(), + }, + ...libraryItems, + ]; + onAddToLibrary(); + library.setLibrary(nextItems).catch(() => { + setAppState({ errorMessage: t("alerts.errorAddingToLibrary") }); }); - } - const nextItems: LibraryItems = [ - { - status: "unpublished", - elements, - id: randomId(), - created: Date.now(), - }, - ...libraryItems, - ]; - onAddToLibrary(); - library.setLibrary(nextItems).catch(() => { - setAppState({ errorMessage: t("alerts.errorAddingToLibrary") }); - }); + }; + addToLibrary(elements, libraryItemsData.libraryItems); }, - [onAddToLibrary, library, setAppState], + [onAddToLibrary, library, setAppState, libraryItemsData.libraryItems], + ); + + const libraryItems = useMemo( + () => libraryItemsData.libraryItems, + [libraryItemsData], ); if ( @@ -103,15 +121,15 @@ export const LibraryMenuContent = ({ - addToLibrary(elements, libraryItemsData.libraryItems) - } + libraryItems={libraryItems} + onAddToLibrary={_onAddToLibrary} onInsertLibraryItems={onInsertLibraryItems} pendingElements={pendingElements} id={id} libraryReturnUrl={libraryReturnUrl} - theme={appState.theme} + theme={theme} + onSelectItems={onSelectItems} + selectedItems={selectedItems} /> {showBtn && ( )} ); }; +const usePendingElementsMemo = ( + appState: UIAppState, + elements: readonly NonDeletedExcalidrawElement[], +) => { + const create = () => getSelectedElements(elements, appState, true); + const val = useRef(create()); + const prevAppState = useRef(appState); + const prevElements = useRef(elements); + + if ( + !isShallowEqual( + appState.selectedElementIds, + prevAppState.current.selectedElementIds, + ) || + !isShallowEqual(elements, prevElements.current) + ) { + val.current = create(); + prevAppState.current = appState; + prevElements.current = elements; + } + return val.current; +}; + /** * This component is meant to be rendered inside inside our * or host apps Sidebar components. @@ -136,9 +177,19 @@ export const LibraryMenu = () => { const appState = useUIAppState(); const setAppState = useExcalidrawSetAppState(); const elements = useExcalidrawElements(); + const [selectedItems, setSelectedItems] = useState([]); + const memoizedLibrary = useMemo(() => library, [library]); + // BUG: pendingElements are still causing some unnecessary rerenders because clicking into canvas returns some ids even when no element is selected. + const pendingElements = usePendingElementsMemo(appState, elements); - const onAddToLibrary = useCallback(() => { - // deselect canvas elements + const onInsertLibraryItems = useCallback( + (libraryItems: LibraryItems) => { + onInsertElements(distributeLibraryItemsOnSquareGrid(libraryItems)); + }, + [onInsertElements], + ); + + const deselectItems = useCallback(() => { setAppState({ selectedElementIds: {}, selectedGroupIds: {}, @@ -147,16 +198,16 @@ export const LibraryMenu = () => { return ( { - onInsertElements(distributeLibraryItemsOnSquareGrid(libraryItems)); - }} - onAddToLibrary={onAddToLibrary} + pendingElements={pendingElements} + onInsertLibraryItems={onInsertLibraryItems} + onAddToLibrary={deselectItems} setAppState={setAppState} libraryReturnUrl={appProps.libraryReturnUrl} - library={library} + library={memoizedLibrary} id={id} - appState={appState} + theme={appState.theme} + selectedItems={selectedItems} + onSelectItems={setSelectedItems} /> ); }; diff --git a/src/components/LibraryMenuItems.scss b/src/components/LibraryMenuItems.scss index 1a3fa9715..8ac09aabc 100644 --- a/src/components/LibraryMenuItems.scss +++ b/src/components/LibraryMenuItems.scss @@ -73,6 +73,12 @@ } } + &__grid { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-gap: 1rem; + } + .separator { width: 100%; display: flex; diff --git a/src/components/LibraryMenuItems.tsx b/src/components/LibraryMenuItems.tsx index 8dd6b30f2..ff88e537c 100644 --- a/src/components/LibraryMenuItems.tsx +++ b/src/components/LibraryMenuItems.tsx @@ -1,4 +1,10 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; import { serializeLibraryAsJSON } from "../data/json"; import { t } from "../i18n"; import { @@ -14,12 +20,22 @@ import Spinner from "./Spinner"; import { duplicateElements } from "../element/newElement"; import { LibraryMenuControlButtons } from "./LibraryMenuControlButtons"; import { LibraryDropdownMenu } from "./LibraryMenuHeaderContent"; -import LibraryMenuSection from "./LibraryMenuSection"; +import { + LibraryMenuSection, + LibraryMenuSectionGrid, +} from "./LibraryMenuSection"; import { useScrollPosition } from "../hooks/useScrollPosition"; import { useLibraryCache } from "../hooks/useLibraryItemSvg"; import "./LibraryMenuItems.scss"; +// using an odd number of items per batch so the rendering creates an irregular +// pattern which looks more organic +const ITEMS_RENDERED_PER_BATCH = 17; +// when render outputs cached we can render many more items per batch to +// speed it up +const CACHED_ITEMS_RENDERED_PER_BATCH = 64; + export default function LibraryMenuItems({ isLoading, libraryItems, @@ -29,6 +45,8 @@ export default function LibraryMenuItems({ theme, id, libraryReturnUrl, + onSelectItems, + selectedItems, }: { isLoading: boolean; libraryItems: LibraryItems; @@ -38,8 +56,9 @@ export default function LibraryMenuItems({ libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"]; theme: UIAppState["theme"]; id: string; + selectedItems: LibraryItem["id"][]; + onSelectItems: (id: LibraryItem["id"][]) => void; }) { - const [selectedItems, setSelectedItems] = useState([]); const libraryContainerRef = useRef(null); const scrollPosition = useScrollPosition(libraryContainerRef); @@ -49,13 +68,16 @@ export default function LibraryMenuItems({ libraryContainerRef.current?.scrollTo(0, scrollPosition); } }, []); // eslint-disable-line react-hooks/exhaustive-deps - const { svgCache } = useLibraryCache(); - const unpublishedItems = libraryItems.filter( - (item) => item.status !== "published", + const { svgCache } = useLibraryCache(); + const unpublishedItems = useMemo( + () => libraryItems.filter((item) => item.status !== "published"), + [libraryItems], ); - const publishedItems = libraryItems.filter( - (item) => item.status === "published", + + const publishedItems = useMemo( + () => libraryItems.filter((item) => item.status === "published"), + [libraryItems], ); const showBtn = !libraryItems.length && !pendingElements.length; @@ -69,50 +91,56 @@ export default function LibraryMenuItems({ LibraryItem["id"] | null >(null); - const onItemSelectToggle = ( - id: LibraryItem["id"], - event: React.MouseEvent, - ) => { - const shouldSelect = !selectedItems.includes(id); + const onItemSelectToggle = useCallback( + (id: LibraryItem["id"], event: React.MouseEvent) => { + const shouldSelect = !selectedItems.includes(id); - const orderedItems = [...unpublishedItems, ...publishedItems]; + const orderedItems = [...unpublishedItems, ...publishedItems]; - if (shouldSelect) { - if (event.shiftKey && lastSelectedItem) { - const rangeStart = orderedItems.findIndex( - (item) => item.id === lastSelectedItem, - ); - const rangeEnd = orderedItems.findIndex((item) => item.id === id); + if (shouldSelect) { + if (event.shiftKey && lastSelectedItem) { + const rangeStart = orderedItems.findIndex( + (item) => item.id === lastSelectedItem, + ); + const rangeEnd = orderedItems.findIndex((item) => item.id === id); - if (rangeStart === -1 || rangeEnd === -1) { - setSelectedItems([...selectedItems, id]); - return; + if (rangeStart === -1 || rangeEnd === -1) { + onSelectItems([...selectedItems, id]); + return; + } + + const selectedItemsMap = arrayToMap(selectedItems); + const nextSelectedIds = orderedItems.reduce( + (acc: LibraryItem["id"][], item, idx) => { + if ( + (idx >= rangeStart && idx <= rangeEnd) || + selectedItemsMap.has(item.id) + ) { + acc.push(item.id); + } + return acc; + }, + [], + ); + + onSelectItems(nextSelectedIds); + } else { + onSelectItems([...selectedItems, id]); } - - const selectedItemsMap = arrayToMap(selectedItems); - const nextSelectedIds = orderedItems.reduce( - (acc: LibraryItem["id"][], item, idx) => { - if ( - (idx >= rangeStart && idx <= rangeEnd) || - selectedItemsMap.has(item.id) - ) { - acc.push(item.id); - } - return acc; - }, - [], - ); - - setSelectedItems(nextSelectedIds); + setLastSelectedItem(id); } else { - setSelectedItems([...selectedItems, id]); + setLastSelectedItem(null); + onSelectItems(selectedItems.filter((_id) => _id !== id)); } - setLastSelectedItem(id); - } else { - setLastSelectedItem(null); - setSelectedItems(selectedItems.filter((_id) => _id !== id)); - } - }; + }, + [ + lastSelectedItem, + onSelectItems, + publishedItems, + selectedItems, + unpublishedItems, + ], + ); const getInsertedElements = useCallback( (id: string) => { @@ -136,37 +164,45 @@ export default function LibraryMenuItems({ [libraryItems, selectedItems], ); - const onItemDrag = (id: LibraryItem["id"], event: React.DragEvent) => { - event.dataTransfer.setData( - MIME_TYPES.excalidrawlib, - serializeLibraryAsJSON(getInsertedElements(id)), - ); - }; + const onItemDrag = useCallback( + (id: LibraryItem["id"], event: React.DragEvent) => { + event.dataTransfer.setData( + MIME_TYPES.excalidrawlib, + serializeLibraryAsJSON(getInsertedElements(id)), + ); + }, + [getInsertedElements], + ); - const isItemSelected = (id: LibraryItem["id"] | null) => { - if (!id) { - return false; - } + const isItemSelected = useCallback( + (id: LibraryItem["id"] | null) => { + if (!id) { + return false; + } - return selectedItems.includes(id); - }; + return selectedItems.includes(id); + }, + [selectedItems], + ); + + const onAddToLibraryClick = useCallback(() => { + onAddToLibrary(pendingElements); + }, [pendingElements, onAddToLibrary]); const onItemClick = useCallback( (id: LibraryItem["id"] | null) => { - if (!id) { - onAddToLibrary(pendingElements); - } else { + if (id) { onInsertLibraryItems(getInsertedElements(id)); } }, - [ - getInsertedElements, - onAddToLibrary, - onInsertLibraryItems, - pendingElements, - ], + [getInsertedElements, onInsertLibraryItems], ); + const itemsRenderedPerBatch = + svgCache.size >= libraryItems.length + ? CACHED_ITEMS_RENDERED_PER_BATCH + : ITEMS_RENDERED_PER_BATCH; + return (
)} @@ -225,20 +261,28 @@ export default function LibraryMenuItems({
) : ( - + + {pendingElements.length > 0 && ( + + )} + + )} @@ -251,14 +295,17 @@ export default function LibraryMenuItems({
)} {publishedItems.length > 0 ? ( - + + + ) : unpublishedItems.length > 0 ? (
)} diff --git a/src/components/LibraryMenuSection.tsx b/src/components/LibraryMenuSection.tsx index 496f045b7..0e10470fc 100644 --- a/src/components/LibraryMenuSection.tsx +++ b/src/components/LibraryMenuSection.tsx @@ -1,16 +1,10 @@ -import React, { useEffect, useMemo, useState } from "react"; -import { LibraryUnit } from "./LibraryUnit"; +import React, { memo, ReactNode, useEffect, useState } from "react"; +import { EmptyLibraryUnit, LibraryUnit } from "./LibraryUnit"; import { LibraryItem } from "../types"; -import Stack from "./Stack"; -import clsx from "clsx"; import { ExcalidrawElement, NonDeleted } from "../element/types"; import { SvgCache } from "../hooks/useLibraryItemSvg"; import { useTransition } from "../hooks/useTransition"; -const ITEMS_PER_ROW = 4; -const ROWS_RENDERED_PER_BATCH = 6; -const CACHED_ROWS_RENDERED_PER_BATCH = 16; - type LibraryOrPendingItem = ( | LibraryItem | /* pending library item */ { @@ -26,91 +20,58 @@ interface Props { onItemDrag: (id: LibraryItem["id"], event: React.DragEvent) => void; isItemSelected: (id: LibraryItem["id"] | null) => boolean; svgCache: SvgCache; + itemsRenderedPerBatch: number; } -function LibraryRow({ - items, - onItemSelectToggle, - onItemDrag, - isItemSelected, - onClick, - svgCache, -}: Props) { - return ( - - {items.map((item) => ( - - - - ))} - - ); -} +export const LibraryMenuSectionGrid = ({ + children, +}: { + children: ReactNode; +}) => { + return
{children}
; +}; -const EmptyLibraryRow = () => ( - - {Array.from({ length: ITEMS_PER_ROW }).map((_, index) => ( - -
- - ))} - +export const LibraryMenuSection = memo( + ({ + items, + onItemSelectToggle, + onItemDrag, + isItemSelected, + onClick, + svgCache, + itemsRenderedPerBatch, + }: Props) => { + const [, startTransition] = useTransition(); + const [index, setIndex] = useState(0); + + useEffect(() => { + if (index < items.length) { + startTransition(() => { + setIndex(index + itemsRenderedPerBatch); + }); + } + }, [index, items.length, startTransition, itemsRenderedPerBatch]); + + return ( + <> + {items.map((item, i) => { + return i < index ? ( + + ) : ( + + ); + })} + + ); + }, ); - -function LibraryMenuSection({ - items, - onItemSelectToggle, - onItemDrag, - isItemSelected, - onClick, - svgCache, -}: Props) { - const rows = Math.ceil(items.length / ITEMS_PER_ROW); - const [, startTransition] = useTransition(); - const [index, setIndex] = useState(0); - - const rowsRenderedPerBatch = useMemo(() => { - return svgCache.size === 0 - ? ROWS_RENDERED_PER_BATCH - : CACHED_ROWS_RENDERED_PER_BATCH; - }, [svgCache]); - - useEffect(() => { - if (index < rows) { - startTransition(() => { - setIndex(index + rowsRenderedPerBatch); - }); - } - }, [index, rows, startTransition, rowsRenderedPerBatch]); - - return ( - <> - {Array.from({ length: rows }).map((_, i) => - i < index ? ( - - ) : ( - - ), - )} - - ); -} - -export default LibraryMenuSection; diff --git a/src/components/LibraryUnit.scss b/src/components/LibraryUnit.scss index 1bfc1e6df..a5f26bff4 100644 --- a/src/components/LibraryUnit.scss +++ b/src/components/LibraryUnit.scss @@ -30,7 +30,7 @@ var(--color-gray-10) ); background-size: 200% 200%; - animation: library-unit__skeleton-opacity-animation 0.3s linear; + animation: library-unit__skeleton-opacity-animation 0.2s linear; } } diff --git a/src/components/LibraryUnit.tsx b/src/components/LibraryUnit.tsx index f256b49f1..ce5d4ebbb 100644 --- a/src/components/LibraryUnit.tsx +++ b/src/components/LibraryUnit.tsx @@ -1,5 +1,5 @@ import clsx from "clsx"; -import { useEffect, useRef, useState } from "react"; +import { memo, useEffect, useRef, useState } from "react"; import { useDevice } from "../components/App"; import { LibraryItem } from "../types"; import "./LibraryUnit.scss"; @@ -7,96 +7,101 @@ import { CheckboxItem } from "./CheckboxItem"; import { PlusIcon } from "./icons"; import { SvgCache, useLibraryItemSvg } from "../hooks/useLibraryItemSvg"; -export const LibraryUnit = ({ - id, - elements, - isPending, - onClick, - selected, - onToggle, - onDrag, - svgCache, -}: { - id: LibraryItem["id"] | /** for pending item */ null; - elements?: LibraryItem["elements"]; - isPending?: boolean; - onClick: (id: LibraryItem["id"] | null) => void; - selected: boolean; - onToggle: (id: string, event: React.MouseEvent) => void; - onDrag: (id: string, event: React.DragEvent) => void; - svgCache: SvgCache; -}) => { - const ref = useRef(null); - const svg = useLibraryItemSvg(id, elements, svgCache); +export const LibraryUnit = memo( + ({ + id, + elements, + isPending, + onClick, + selected, + onToggle, + onDrag, + svgCache, + }: { + id: LibraryItem["id"] | /** for pending item */ null; + elements?: LibraryItem["elements"]; + isPending?: boolean; + onClick: (id: LibraryItem["id"] | null) => void; + selected: boolean; + onToggle: (id: string, event: React.MouseEvent) => void; + onDrag: (id: string, event: React.DragEvent) => void; + svgCache: SvgCache; + }) => { + const ref = useRef(null); + const svg = useLibraryItemSvg(id, elements, svgCache); - useEffect(() => { - const node = ref.current; + useEffect(() => { + const node = ref.current; - if (!node) { - return; - } + if (!node) { + return; + } - if (svg) { - svg.querySelector(".style-fonts")?.remove(); - node.innerHTML = svg.outerHTML; - } + if (svg) { + node.innerHTML = svg.outerHTML; + } - return () => { - node.innerHTML = ""; - }; - }, [elements, svg]); + return () => { + node.innerHTML = ""; + }; + }, [svg]); - const [isHovered, setIsHovered] = useState(false); - const isMobile = useDevice().isMobile; - const adder = isPending && ( -
{PlusIcon}
- ); + const [isHovered, setIsHovered] = useState(false); + const isMobile = useDevice().isMobile; + const adder = isPending && ( +
{PlusIcon}
+ ); - return ( -
setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - > + return (
{ - if (id && event.shiftKey) { - onToggle(id, event); - } else { - onClick(id); + onMouseEnter={() => setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + > +
{ + if (id && event.shiftKey) { + onToggle(id, event); + } else { + onClick(id); + } } - } - : undefined - } - onDragStart={(event) => { - if (!id) { - event.preventDefault(); - return; + : undefined } - setIsHovered(false); - onDrag(id, event); - }} - /> - {adder} - {id && elements && (isHovered || isMobile || selected) && ( - onToggle(id, event)} - className="library-unit__checkbox" + onDragStart={(event) => { + if (!id) { + event.preventDefault(); + return; + } + setIsHovered(false); + onDrag(id, event); + }} /> - )} -
- ); -}; + {adder} + {id && elements && (isHovered || isMobile || selected) && ( + onToggle(id, event)} + className="library-unit__checkbox" + /> + )} +
+ ); + }, +); + +export const EmptyLibraryUnit = () => ( +
+); diff --git a/src/hooks/useLibraryItemSvg.ts b/src/hooks/useLibraryItemSvg.ts index ba9802199..1c27f0ce7 100644 --- a/src/hooks/useLibraryItemSvg.ts +++ b/src/hooks/useLibraryItemSvg.ts @@ -39,6 +39,7 @@ export const useLibraryItemSvg = ( // When there is no svg in cache export it and save to cache (async () => { const exportedSvg = await exportLibraryItemToSvg(elements); + exportedSvg.querySelector(".style-fonts")?.remove(); if (exportedSvg) { svgCache.set(id, exportedSvg); From 7bf4de5892a1ef7899b0f701ded79ad835b7a1b2 Mon Sep 17 00:00:00 2001 From: Are Date: Wed, 31 May 2023 18:27:29 +0200 Subject: [PATCH 087/451] feat: redesign of Live Collaboration dialog (#6635) * feat: redesiged Live Collaboration dialog * fix: address lints * fix: inactive dialog dark mode improvements * fix: follow styleguide with event parameter, add FilledButton size prop * fix: change timer to be imperative * fix: add spacing after emoji * fix: remove unused useEffect * fix: change margin into whitespace * fix: add share button check back --- src/assets/lock.svg | 20 ++ src/components/FilledButton.scss | 95 +++++++ src/components/FilledButton.tsx | 61 +++++ src/components/ImageExportDialog.scss | 42 ---- src/components/ImageExportDialog.tsx | 38 +-- src/components/Switch.tsx | 4 +- src/components/TextField.scss | 118 +++++++++ src/components/TextField.tsx | 57 +++++ src/components/icons.tsx | 28 +++ src/css/theme.scss | 2 + src/excalidraw-app/collab/RoomDialog.scss | 191 +++++++++----- src/excalidraw-app/collab/RoomDialog.tsx | 293 ++++++++++++---------- src/excalidraw-app/index.tsx | 2 +- 13 files changed, 698 insertions(+), 253 deletions(-) create mode 100644 src/assets/lock.svg create mode 100644 src/components/FilledButton.scss create mode 100644 src/components/FilledButton.tsx create mode 100644 src/components/TextField.scss create mode 100644 src/components/TextField.tsx diff --git a/src/assets/lock.svg b/src/assets/lock.svg new file mode 100644 index 000000000..aa9dbf170 --- /dev/null +++ b/src/assets/lock.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/FilledButton.scss b/src/components/FilledButton.scss new file mode 100644 index 000000000..d742e22e7 --- /dev/null +++ b/src/components/FilledButton.scss @@ -0,0 +1,95 @@ +@import "../css/variables.module"; + +.excalidraw { + .ExcButton { + &--color-primary { + color: var(--input-bg-color); + + --accent-color: var(--color-primary); + --accent-color-hover: var(--color-primary-darker); + --accent-color-active: var(--color-primary-darkest); + } + + &--color-danger { + color: var(--input-bg-color); + + --accent-color: var(--color-danger); + --accent-color-hover: #d65550; + --accent-color-active: #d1413c; + } + + display: flex; + justify-content: center; + align-items: center; + flex-shrink: 0; + flex-wrap: nowrap; + + border-radius: 0.5rem; + + font-family: "Assistant"; + + user-select: none; + + transition: all 150ms ease-out; + + &--size-large { + font-weight: 400; + font-size: 0.875rem; + height: 3rem; + padding: 0.5rem 1.5rem; + gap: 0.75rem; + + letter-spacing: 0.4px; + } + + &--size-medium { + font-weight: 600; + font-size: 0.75rem; + height: 2.5rem; + padding: 0.5rem 1rem; + gap: 0.5rem; + + letter-spacing: normal; + } + + &--variant-filled { + background: var(--accent-color); + border: 1px solid transparent; + + &:hover { + background: var(--accent-color-hover); + } + + &:active { + background: var(--accent-color-active); + } + } + + &--variant-outlined, + &--variant-icon { + border: 1px solid var(--accent-color); + color: var(--accent-color); + background: transparent; + + &:hover { + border: 1px solid var(--accent-color-hover); + color: var(--accent-color-hover); + } + + &:active { + border: 1px solid var(--accent-color-active); + color: var(--accent-color-active); + } + } + + &--variant-icon { + padding: 0.5rem 0.75rem; + width: 3rem; + } + + &__icon { + width: 1.25rem; + height: 1.25rem; + } + } +} diff --git a/src/components/FilledButton.tsx b/src/components/FilledButton.tsx new file mode 100644 index 000000000..0db724216 --- /dev/null +++ b/src/components/FilledButton.tsx @@ -0,0 +1,61 @@ +import React, { forwardRef } from "react"; +import clsx from "clsx"; + +import "./FilledButton.scss"; + +export type ButtonVariant = "filled" | "outlined" | "icon"; +export type ButtonColor = "primary" | "danger"; +export type ButtonSize = "medium" | "large"; + +export type FilledButtonProps = { + label: string; + + children?: React.ReactNode; + onClick?: () => void; + + variant?: ButtonVariant; + color?: ButtonColor; + size?: ButtonSize; + className?: string; + + startIcon?: React.ReactNode; +}; + +export const FilledButton = forwardRef( + ( + { + children, + startIcon, + onClick, + label, + variant = "filled", + color = "primary", + size = "medium", + className, + }, + ref, + ) => { + return ( + + ); + }, +); diff --git a/src/components/ImageExportDialog.scss b/src/components/ImageExportDialog.scss index a74cfdc20..093e1a76f 100644 --- a/src/components/ImageExportDialog.scss +++ b/src/components/ImageExportDialog.scss @@ -167,48 +167,6 @@ flex-basis: 100%; justify-content: center; } - - &__button { - box-sizing: border-box; - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - padding: 8px 16px; - flex-shrink: 0; - width: fit-content; - gap: 8px; - - height: 40px; - border: 0; - border-radius: 8px; - - user-select: none; - font-family: "Assistant"; - font-style: normal; - font-weight: 600; - font-size: 0.75rem; - line-height: 100%; - transition: 150ms ease-out; - transition-property: background, color; - - background: var(--color-primary); - color: var(--color-icon-white); - - &:hover { - background: var(--color-primary-darker); - color: var(--color-icon-white); - } - - &:active { - background: var(--color-primary-darkest); - } - - & > svg { - width: 20px; - height: 20px; - } - } } } } diff --git a/src/components/ImageExportDialog.tsx b/src/components/ImageExportDialog.tsx index 604f50b4f..042d5a3fb 100644 --- a/src/components/ImageExportDialog.tsx +++ b/src/components/ImageExportDialog.tsx @@ -26,7 +26,6 @@ import { getSelectedElements, isSomeElementSelected } from "../scene"; import { exportToCanvas } from "../packages/utils"; import { copyIcon, downloadIcon, helpIcon } from "./icons"; -import { Button } from "./Button"; import { Dialog } from "./Dialog"; import { RadioGroup } from "./RadioGroup"; import { Switch } from "./Switch"; @@ -34,6 +33,7 @@ import { Tooltip } from "./Tooltip"; import "./ImageExportDialog.scss"; import { useAppProps } from "./App"; +import { FilledButton } from "./FilledButton"; const supportsContextFilters = "filter" in document.createElement("canvas").getContext("2d")!; @@ -236,37 +236,37 @@ const ImageExportModal = ({
- - + {t("imageExportDialog.button.exportToSvg")} + {(probablySupportsClipboardBlob || isFirefox) && ( - + {t("imageExportDialog.button.copyPngToClipboard")} + )}
diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx index dfbf332fc..431c644f0 100644 --- a/src/components/Switch.tsx +++ b/src/components/Switch.tsx @@ -27,8 +27,8 @@ export const Switch = ({ checked={checked} disabled={disabled} onChange={() => onChange(!checked)} - onKeyDown={(e) => { - if (e.key === " ") { + onKeyDown={(event) => { + if (event.key === " ") { onChange(!checked); } }} diff --git a/src/components/TextField.scss b/src/components/TextField.scss new file mode 100644 index 000000000..57093996c --- /dev/null +++ b/src/components/TextField.scss @@ -0,0 +1,118 @@ +@import "../css/variables.module"; + +.excalidraw { + --ExcTextField--color: var(--color-gray-80); + --ExcTextField--label-color: var(--color-gray-80); + --ExcTextField--background: white; + --ExcTextField--readonly--background: var(--color-gray-10); + --ExcTextField--readonly--color: var(--color-gray-80); + --ExcTextField--border: var(--color-gray-40); + --ExcTextField--border-hover: var(--color-gray-50); + --ExcTextField--placeholder: var(--color-gray-40); + + &.theme--dark { + --ExcTextField--color: var(--color-gray-10); + --ExcTextField--label-color: var(--color-gray-20); + --ExcTextField--background: var(--color-gray-85); + --ExcTextField--readonly--background: var(--color-gray-80); + --ExcTextField--readonly--color: var(--color-gray-40); + --ExcTextField--border: var(--color-gray-70); + --ExcTextField--border-hover: var(--color-gray-60); + --ExcTextField--placeholder: var(--color-gray-80); + } + + .ExcTextField { + &--fullWidth { + width: 100%; + flex-grow: 1; + } + + &__label { + font-family: "Assistant"; + font-style: normal; + font-weight: 600; + font-size: 0.875rem; + line-height: 150%; + + color: var(--ExcTextField--label-color); + + margin-bottom: 0.25rem; + user-select: none; + } + + &__input { + box-sizing: border-box; + + display: flex; + flex-direction: row; + align-items: center; + padding: 0 1rem; + + height: 3rem; + + background: var(--ExcTextField--background); + border: 1px solid var(--ExcTextField--border); + border-radius: 0.5rem; + + &:not(&--readonly) { + &:hover { + border-color: var(--ExcTextField--border-hover); + } + + &:active, + &:focus-within { + border-color: var(--color-primary); + } + } + + & input { + display: flex; + align-items: center; + + border: none; + outline: none; + padding: 0; + margin: 0; + + height: 1.5rem; + + color: var(--ExcTextField--color); + + font-family: "Assistant"; + font-style: normal; + font-weight: 400; + font-size: 1rem; + line-height: 150%; + text-overflow: ellipsis; + + background: transparent; + + width: 100%; + + &::placeholder { + color: var(--ExcTextField--placeholder); + } + + &:not(:focus) { + &:hover { + background-color: initial; + } + } + + &:focus { + outline: initial; + box-shadow: initial; + } + } + + &--readonly { + background: var(--ExcTextField--readonly--background); + border-color: transparent; + + & input { + color: var(--ExcTextField--readonly--color); + } + } + } + } +} diff --git a/src/components/TextField.tsx b/src/components/TextField.tsx new file mode 100644 index 000000000..7f7a41fd0 --- /dev/null +++ b/src/components/TextField.tsx @@ -0,0 +1,57 @@ +import { forwardRef, useRef, useImperativeHandle, KeyboardEvent } from "react"; +import clsx from "clsx"; + +import "./TextField.scss"; + +export type TextFieldProps = { + value?: string; + + onChange?: (value: string) => void; + onClick?: () => void; + onKeyDown?: (event: KeyboardEvent) => void; + + readonly?: boolean; + fullWidth?: boolean; + + label?: string; + placeholder?: string; +}; + +export const TextField = forwardRef( + ( + { value, onChange, label, fullWidth, placeholder, readonly, onKeyDown }, + ref, + ) => { + const innerRef = useRef(null); + + useImperativeHandle(ref, () => innerRef.current!); + + return ( +
{ + innerRef.current?.focus(); + }} + > +
{label}
+
+ onChange?.(event.target.value)} + onKeyDown={onKeyDown} + /> +
+
+ ); + }, +); diff --git a/src/components/icons.tsx b/src/components/icons.tsx index 3841d030e..543248a1a 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -1579,3 +1579,31 @@ export const helpIcon = createIcon( , tablerIconProps, ); + +export const playerPlayIcon = createIcon( + <> + + + , + tablerIconProps, +); + +export const playerStopFilledIcon = createIcon( + <> + + + , + tablerIconProps, +); + +export const tablerCheckIcon = createIcon( + <> + + + , + tablerIconProps, +); diff --git a/src/css/theme.scss b/src/css/theme.scss index c8abc4fff..92b5989a8 100644 --- a/src/css/theme.scss +++ b/src/css/theme.scss @@ -103,6 +103,8 @@ --color-danger: #db6965; --color-promo: #e70078; + --color-success: #268029; + --color-success-lighter: #cafccc; --border-radius-md: 0.375rem; --border-radius-lg: 0.5rem; diff --git a/src/excalidraw-app/collab/RoomDialog.scss b/src/excalidraw-app/collab/RoomDialog.scss index c8bf0dcde..0d1bcad6c 100644 --- a/src/excalidraw-app/collab/RoomDialog.scss +++ b/src/excalidraw-app/collab/RoomDialog.scss @@ -1,76 +1,149 @@ @import "../../css/variables.module"; .excalidraw { - .RoomDialog__button { - border: 1px solid var(--default-border-color) !important; - } - - .RoomDialog-linkContainer { + .RoomDialog { display: flex; - margin: 1.5em 0; - } + flex-direction: column; + gap: 1.5rem; - input.RoomDialog-link { - color: var(--text-primary-color); - min-width: 0; - flex: 1 1 auto; - margin-inline-start: 1em; - display: inline-block; - cursor: pointer; - border: none; - padding: 0 0.5rem; - white-space: nowrap; - border-radius: var(--space-factor); - background-color: var(--button-gray-1); - } - - .RoomDialog-emoji { - font-family: sans-serif; - } - - .RoomDialog-usernameContainer { - display: flex; - margin: 1.5em 0; - display: flex; - align-items: center; - justify-content: center; @include isMobile { - flex-direction: column; - align-items: stretch; + height: calc(100vh - 5rem); } - } - @include isMobile { - .RoomDialog-usernameLabel { - font-weight: bold; + &__popover { + @keyframes RoomDialog__popover__scaleIn { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + box-sizing: border-box; + z-index: 100; + + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-start; + padding: 0.125rem 0.5rem; + gap: 0.125rem; + + height: 1.125rem; + + border: none; + border-radius: 0.6875rem; + + font-family: "Assistant"; + font-style: normal; + font-weight: 600; + font-size: 0.75rem; + line-height: 110%; + + background: var(--color-success-lighter); + color: var(--color-success); + + & > svg { + width: 0.875rem; + height: 0.875rem; + } + + transform-origin: var(--radix-popover-content-transform-origin); + animation: RoomDialog__popover__scaleIn 150ms ease-out; } - } - .RoomDialog-username { - background-color: var(--input-bg-color); - border-color: var(--input-border-color); - appearance: none; - min-width: 0; - flex: 1 1 auto; - margin-inline-start: 1em; - @include isMobile { - margin-top: 0.5em; - margin-inline-start: 0; + &__inactive { + font-family: "Assistant"; + + &__illustration { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + + & svg { + filter: var(--theme-filter); + } + } + + &__header { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + + font-weight: 700; + font-size: 1.3125rem; + line-height: 130%; + + color: var(--color-primary); + } + + &__description { + font-weight: 400; + font-size: 0.875rem; + line-height: 150%; + + text-align: center; + + color: var(--text-primary-color); + + & strong { + display: block; + font-weight: 700; + } + } + + &__start_session { + display: flex; + + align-items: center; + justify-content: center; + } } - font-size: 1em; - } - .RoomDialog-sessionStartButtonContainer { - display: flex; - justify-content: center; - } + &__active { + &__share { + display: none !important; - .Modal .RoomDialog-stopSession { - background-color: var(--button-destructive-bg-color); + @include isMobile { + display: flex !important; + } + } - .ToolIcon__label, - .ToolIcon__icon svg { - color: var(--button-destructive-color); + &__header { + margin: 0; + } + + &__linkRow { + display: flex; + flex-direction: row; + align-items: flex-end; + gap: 0.75rem; + } + + &__description { + border-top: 1px solid var(--color-gray-20); + + padding: 0.5rem 0.5rem 0; + font-weight: 400; + font-size: 0.75rem; + line-height: 150%; + + & p { + margin: 0; + } + + & p + p { + margin-top: 1em; + } + } + + &__actions { + display: flex; + justify-content: center; + } } } } diff --git a/src/excalidraw-app/collab/RoomDialog.tsx b/src/excalidraw-app/collab/RoomDialog.tsx index 05772774a..daec8cfe9 100644 --- a/src/excalidraw-app/collab/RoomDialog.tsx +++ b/src/excalidraw-app/collab/RoomDialog.tsx @@ -1,24 +1,29 @@ -import React, { useRef } from "react"; +import { useRef, useState } from "react"; +import * as Popover from "@radix-ui/react-popover"; + import { copyTextToSystemClipboard } from "../../clipboard"; -import { Dialog } from "../../components/Dialog"; -import { - clipboard, - start, - stop, - share, - shareIOS, - shareWindows, -} from "../../components/icons"; -import { ToolButton } from "../../components/ToolButton"; -import "./RoomDialog.scss"; -import Stack from "../../components/Stack"; import { AppState } from "../../types"; import { trackEvent } from "../../analytics"; import { getFrame } from "../../utils"; -import DialogActionButton from "../../components/DialogActionButton"; import { useI18n } from "../../i18n"; import { KEYS } from "../../keys"; +import { Dialog } from "../../components/Dialog"; +import { + copyIcon, + playerPlayIcon, + playerStopFilledIcon, + share, + shareIOS, + shareWindows, + tablerCheckIcon, +} from "../../components/icons"; +import { TextField } from "../../components/TextField"; +import { FilledButton } from "../../components/FilledButton"; + +import { ReactComponent as CollabImage } from "../../assets/lock.svg"; +import "./RoomDialog.scss"; + const getShareIcon = () => { const navigator = window.navigator as any; const isAppleBrowser = /Apple/.test(navigator.vendor); @@ -33,16 +38,7 @@ const getShareIcon = () => { return share; }; -const RoomDialog = ({ - handleClose, - activeRoomLink, - username, - onUsernameChange, - onRoomCreate, - onRoomDestroy, - setErrorMessage, - theme, -}: { +export type RoomModalProps = { handleClose: () => void; activeRoomLink: string; username: string; @@ -51,19 +47,41 @@ const RoomDialog = ({ onRoomDestroy: () => void; setErrorMessage: (message: string) => void; theme: AppState["theme"]; -}) => { +}; + +export const RoomModal = ({ + activeRoomLink, + onRoomCreate, + onRoomDestroy, + setErrorMessage, + username, + onUsernameChange, + handleClose, +}: RoomModalProps) => { const { t } = useI18n(); - const roomLinkInput = useRef(null); + const [justCopied, setJustCopied] = useState(false); + const timerRef = useRef(0); + const ref = useRef(null); + const isShareSupported = "share" in navigator; const copyRoomLink = async () => { try { await copyTextToSystemClipboard(activeRoomLink); + + setJustCopied(true); + + if (timerRef.current) { + window.clearTimeout(timerRef.current); + } + + timerRef.current = window.setTimeout(() => { + setJustCopied(false); + }, 3000); } catch (error: any) { setErrorMessage(error.message); } - if (roomLinkInput.current) { - roomLinkInput.current.select(); - } + + ref.current?.select(); }; const shareRoomLink = async () => { @@ -78,114 +96,129 @@ const RoomDialog = ({ } }; - const selectInput = (event: React.MouseEvent) => { - if (event.target !== document.activeElement) { - event.preventDefault(); - (event.target as HTMLInputElement).select(); - } - }; - - const renderRoomDialog = () => { + if (activeRoomLink) { return ( -
- {!activeRoomLink && ( - <> -

{t("roomDialog.desc_intro")}

-

{`🔒 ${t("roomDialog.desc_privacy")}`}

-
- { - trackEvent("share", "room creation", `ui (${getFrame()})`); - onRoomCreate(); - }} - > - {start} - -
- - )} - {activeRoomLink && ( - <> -

{t("roomDialog.desc_inProgressIntro")}

-

{t("roomDialog.desc_shareLink")}

-
- - {"share" in navigator ? ( - - ) : null} - - - +

+ {t("labels.liveCollaboration")} +

+ event.key === KEYS.ENTER && handleClose()} + /> +
+ + {isShareSupported && ( + + )} + + + -
-
- - onUsernameChange(event.target.value)} - onKeyPress={(event) => - event.key === KEYS.ENTER && handleClose() - } - /> -
-

- - {t("roomDialog.desc_privacy")} -

-

{t("roomDialog.desc_exitSession")}

-
- { - trackEvent("share", "room closed"); - onRoomDestroy(); - }} - > - {stop} - -
- - )} -
+ + event.preventDefault()} + onCloseAutoFocus={(event) => event.preventDefault()} + className="RoomDialog__popover" + side="top" + align="end" + sideOffset={5.5} + > + {tablerCheckIcon} copied + + +
+
+

+ + {t("roomDialog.desc_privacy")} +

+

{t("roomDialog.desc_exitSession")}

+
+ +
+ { + trackEvent("share", "room closed"); + onRoomDestroy(); + }} + /> +
+ ); - }; + } + + return ( + <> +
+ +
+
+ {t("labels.liveCollaboration")} +
+ +
+ {t("roomDialog.desc_intro")} + {t("roomDialog.desc_privacy")} +
+ +
+ { + trackEvent("share", "room creation", `ui (${getFrame()})`); + onRoomCreate(); + }} + /> +
+ + ); +}; + +const RoomDialog = (props: RoomModalProps) => { return ( - {renderRoomDialog()} +
+ +
); }; diff --git a/src/excalidraw-app/index.tsx b/src/excalidraw-app/index.tsx index 9017bbb87..e1af54807 100644 --- a/src/excalidraw-app/index.tsx +++ b/src/excalidraw-app/index.tsx @@ -671,8 +671,8 @@ const ExcalidrawWrapper = () => { {t("alerts.collabOfflineWarning")}
)} + {excalidrawAPI && } - {excalidrawAPI && } {errorMessage && ( setErrorMessage("")}> {errorMessage} From 644685a5a8a016b813b3add36de026f5ead5c4c9 Mon Sep 17 00:00:00 2001 From: Sudharsan Aravind <63002244+vsaravind01@users.noreply.github.com> Date: Fri, 2 Jun 2023 02:47:22 +0530 Subject: [PATCH 088/451] fix: color picker input closing problem (#6599) --- src/components/ColorPicker/ColorPicker.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/ColorPicker/ColorPicker.tsx b/src/components/ColorPicker/ColorPicker.tsx index 25ac7c1a8..c470cc088 100644 --- a/src/components/ColorPicker/ColorPicker.tsx +++ b/src/components/ColorPicker/ColorPicker.tsx @@ -66,7 +66,6 @@ const ColorPickerPopupContent = ({ | "color" | "onChange" | "label" - | "label" | "elements" | "palette" | "updateData" @@ -100,6 +99,8 @@ const ColorPickerPopupContent = ({ container.focus(); } + updateData({ openPopup: null }); + e.preventDefault(); e.stopPropagation(); From 079aa72475f60dfeb4221ade4e9e4e6e1edfbb59 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Fri, 2 Jun 2023 17:06:11 +0200 Subject: [PATCH 089/451] feat: eye dropper (#6615) --- package.json | 2 +- src/actions/actionProperties.tsx | 32 +-- src/colors.ts | 3 + src/components/App.tsx | 94 ++++++-- src/components/ColorPicker/ColorInput.tsx | 71 +++++- src/components/ColorPicker/ColorPicker.scss | 1 + src/components/ColorPicker/ColorPicker.tsx | 76 ++++++- .../ColorPicker/CustomColorList.tsx | 2 +- src/components/ColorPicker/Picker.tsx | 50 ++-- .../ColorPicker/PickerColorList.tsx | 8 +- src/components/ColorPicker/ShadeList.tsx | 8 +- src/components/ColorPicker/TopPicks.tsx | 2 +- .../ColorPicker/colorPickerUtils.ts | 15 +- .../ColorPicker/keyboardNavHandlers.ts | 102 ++++++--- src/components/Dialog.tsx | 3 - src/components/EyeDropper.scss | 48 ++++ src/components/EyeDropper.tsx | 215 ++++++++++++++++++ src/components/HelpDialog.tsx | 4 + src/components/LayerUI.tsx | 25 +- src/components/Modal.tsx | 51 +---- src/components/Sidebar/Sidebar.tsx | 35 +-- .../dropdownMenu/DropdownMenuContent.tsx | 9 +- src/components/icons.tsx | 9 + src/constants.ts | 1 + src/excalidraw-app/collab/Collab.tsx | 1 - src/excalidraw-app/collab/RoomDialog.tsx | 9 +- src/hooks/useCreatePortalContainer.ts | 49 ++++ src/hooks/useOutsideClick.ts | 116 +++++++--- src/locales/en.json | 3 +- src/types.ts | 1 + yarn.lock | 8 +- 31 files changed, 803 insertions(+), 250 deletions(-) create mode 100644 src/components/EyeDropper.scss create mode 100644 src/components/EyeDropper.tsx create mode 100644 src/hooks/useCreatePortalContainer.ts diff --git a/package.json b/package.json index 246c785a5..91a4400b6 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "i18next-browser-languagedetector": "6.1.4", "idb-keyval": "6.0.3", "image-blob-reduce": "3.0.1", - "jotai": "1.6.4", + "jotai": "1.13.1", "lodash.throttle": "4.1.1", "nanoid": "3.3.3", "open-color": "1.9.1", diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index 6e921d6ea..d319337c3 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -119,8 +119,8 @@ const getFormValue = function ( elements: readonly ExcalidrawElement[], appState: AppState, getAttribute: (element: ExcalidrawElement) => T, - defaultValue?: T, -): T | null { + defaultValue: T, +): T { const editingElement = appState.editingElement; const nonDeletedElements = getNonDeletedElements(elements); return ( @@ -132,7 +132,7 @@ const getFormValue = function ( getAttribute, ) : defaultValue) ?? - null + defaultValue ); }; @@ -811,6 +811,7 @@ export const actionChangeTextAlign = register({ ); }, }); + export const actionChangeVerticalAlign = register({ name: "changeVerticalAlign", trackEvent: { category: "element" }, @@ -865,16 +866,21 @@ export const actionChangeVerticalAlign = register({ testId: "align-bottom", }, ]} - value={getFormValue(elements, appState, (element) => { - if (isTextElement(element) && element.containerId) { - return element.verticalAlign; - } - const boundTextElement = getBoundTextElement(element); - if (boundTextElement) { - return boundTextElement.verticalAlign; - } - return null; - })} + value={getFormValue( + elements, + appState, + (element) => { + if (isTextElement(element) && element.containerId) { + return element.verticalAlign; + } + const boundTextElement = getBoundTextElement(element); + if (boundTextElement) { + return boundTextElement.verticalAlign; + } + return null; + }, + VERTICAL_ALIGN.MIDDLE, + )} onChange={(value) => updateData(value)} />
diff --git a/src/colors.ts b/src/colors.ts index 198ec12e2..7da128399 100644 --- a/src/colors.ts +++ b/src/colors.ts @@ -164,4 +164,7 @@ export const getAllColorsSpecificShade = (index: 0 | 1 | 2 | 3 | 4) => COLOR_PALETTE.red[index], ] as const; +export const rgbToHex = (r: number, g: number, b: number) => + `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; + // ----------------------------------------------------------------------------- diff --git a/src/components/App.tsx b/src/components/App.tsx index 0b730fc47..f4c7689bb 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -304,6 +304,7 @@ import { jotaiStore } from "../jotai"; import { activeConfirmDialogAtom } from "./ActiveConfirmDialog"; import { actionWrapTextInContainer } from "../actions/actionBoundText"; import BraveMeasureTextError from "./BraveMeasureTextError"; +import { activeEyeDropperAtom } from "./EyeDropper"; const AppContext = React.createContext(null!); const AppPropsContext = React.createContext(null!); @@ -366,8 +367,6 @@ export const useExcalidrawActionManager = () => let didTapTwice: boolean = false; let tappedTwiceTimer = 0; -let cursorX = 0; -let cursorY = 0; let isHoldingSpace: boolean = false; let isPanning: boolean = false; let isDraggingScrollBar: boolean = false; @@ -425,7 +424,7 @@ class App extends React.Component { hitLinkElement?: NonDeletedExcalidrawElement; lastPointerDown: React.PointerEvent | null = null; lastPointerUp: React.PointerEvent | PointerEvent | null = null; - lastScenePointer: { x: number; y: number } | null = null; + lastViewportPosition = { x: 0, y: 0 }; constructor(props: AppProps) { super(props); @@ -634,6 +633,7 @@ class App extends React.Component {
+
{selectedElement.length === 1 && !this.state.contextMenu && this.state.showHyperlinkPopup && ( @@ -724,6 +724,49 @@ class App extends React.Component { } }; + private openEyeDropper = ({ type }: { type: "stroke" | "background" }) => { + jotaiStore.set(activeEyeDropperAtom, { + swapPreviewOnAlt: true, + previewType: type === "stroke" ? "strokeColor" : "backgroundColor", + onSelect: (color, event) => { + const shouldUpdateStrokeColor = + (type === "background" && event.altKey) || + (type === "stroke" && !event.altKey); + const selectedElements = getSelectedElements( + this.scene.getElementsIncludingDeleted(), + this.state, + ); + if ( + !selectedElements.length || + this.state.activeTool.type !== "selection" + ) { + if (shouldUpdateStrokeColor) { + this.setState({ + currentItemStrokeColor: color, + }); + } else { + this.setState({ + currentItemBackgroundColor: color, + }); + } + } else { + this.updateScene({ + elements: this.scene.getElementsIncludingDeleted().map((el) => { + if (this.state.selectedElementIds[el.id]) { + return newElementWith(el, { + [shouldUpdateStrokeColor ? "strokeColor" : "backgroundColor"]: + color, + }); + } + return el; + }), + }); + } + }, + keepOpenOnAlt: false, + }); + }; + private syncActionResult = withBatchedUpdates( (actionResult: ActionResult) => { if (this.unmounted || actionResult === false) { @@ -1569,7 +1612,10 @@ class App extends React.Component { return; } - const elementUnderCursor = document.elementFromPoint(cursorX, cursorY); + const elementUnderCursor = document.elementFromPoint( + this.lastViewportPosition.x, + this.lastViewportPosition.y, + ); if ( event && (!(elementUnderCursor instanceof HTMLCanvasElement) || @@ -1597,7 +1643,10 @@ class App extends React.Component { // prefer spreadsheet data over image file (MS Office/Libre Office) if (isSupportedImageFile(file) && !data.spreadsheet) { const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords( - { clientX: cursorX, clientY: cursorY }, + { + clientX: this.lastViewportPosition.x, + clientY: this.lastViewportPosition.y, + }, this.state, ); @@ -1660,13 +1709,13 @@ class App extends React.Component { typeof opts.position === "object" ? opts.position.clientX : opts.position === "cursor" - ? cursorX + ? this.lastViewportPosition.x : this.state.width / 2 + this.state.offsetLeft; const clientY = typeof opts.position === "object" ? opts.position.clientY : opts.position === "cursor" - ? cursorY + ? this.lastViewportPosition.y : this.state.height / 2 + this.state.offsetTop; const { x, y } = viewportCoordsToSceneCoords( @@ -1750,7 +1799,10 @@ class App extends React.Component { private addTextFromPaste(text: string, isPlainPaste = false) { const { x, y } = viewportCoordsToSceneCoords( - { clientX: cursorX, clientY: cursorY }, + { + clientX: this.lastViewportPosition.x, + clientY: this.lastViewportPosition.y, + }, this.state, ); @@ -2083,8 +2135,8 @@ class App extends React.Component { private updateCurrentCursorPosition = withBatchedUpdates( (event: MouseEvent) => { - cursorX = event.clientX; - cursorY = event.clientY; + this.lastViewportPosition.x = event.clientX; + this.lastViewportPosition.y = event.clientY; }, ); @@ -2342,6 +2394,20 @@ class App extends React.Component { ) { jotaiStore.set(activeConfirmDialogAtom, "clearCanvas"); } + + // eye dropper + // ----------------------------------------------------------------------- + const lowerCased = event.key.toLocaleLowerCase(); + const isPickingStroke = lowerCased === KEYS.S && event.shiftKey; + const isPickingBackground = + event.key === KEYS.I || (lowerCased === KEYS.G && event.shiftKey); + + if (isPickingStroke || isPickingBackground) { + this.openEyeDropper({ + type: isPickingStroke ? "stroke" : "background", + }); + } + // ----------------------------------------------------------------------- }, ); @@ -2471,8 +2537,8 @@ class App extends React.Component { this.setState((state) => ({ ...getStateForZoom( { - viewportX: cursorX, - viewportY: cursorY, + viewportX: this.lastViewportPosition.x, + viewportY: this.lastViewportPosition.y, nextZoom: getNormalizedZoom(initialScale * event.scale), }, state, @@ -6468,8 +6534,8 @@ class App extends React.Component { this.translateCanvas((state) => ({ ...getStateForZoom( { - viewportX: cursorX, - viewportY: cursorY, + viewportX: this.lastViewportPosition.x, + viewportY: this.lastViewportPosition.y, nextZoom: getNormalizedZoom(newZoom), }, state, diff --git a/src/components/ColorPicker/ColorInput.tsx b/src/components/ColorPicker/ColorInput.tsx index bb9a85510..f179d415c 100644 --- a/src/components/ColorPicker/ColorInput.tsx +++ b/src/components/ColorPicker/ColorInput.tsx @@ -2,15 +2,23 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { getColor } from "./ColorPicker"; import { useAtom } from "jotai"; import { activeColorPickerSectionAtom } from "./colorPickerUtils"; +import { eyeDropperIcon } from "../icons"; +import { jotaiScope } from "../../jotai"; import { KEYS } from "../../keys"; +import { activeEyeDropperAtom } from "../EyeDropper"; +import clsx from "clsx"; +import { t } from "../../i18n"; +import { useDevice } from "../App"; +import { getShortcutKey } from "../../utils"; interface ColorInputProps { - color: string | null; + color: string; onChange: (color: string) => void; label: string; } export const ColorInput = ({ color, onChange, label }: ColorInputProps) => { + const device = useDevice(); const [innerValue, setInnerValue] = useState(color); const [activeSection, setActiveColorPickerSection] = useAtom( activeColorPickerSectionAtom, @@ -34,7 +42,7 @@ export const ColorInput = ({ color, onChange, label }: ColorInputProps) => { ); const inputRef = useRef(null); - const divRef = useRef(null); + const eyeDropperTriggerRef = useRef(null); useEffect(() => { if (inputRef.current) { @@ -42,8 +50,19 @@ export const ColorInput = ({ color, onChange, label }: ColorInputProps) => { } }, [activeSection]); + const [eyeDropperState, setEyeDropperState] = useAtom( + activeEyeDropperAtom, + jotaiScope, + ); + + useEffect(() => { + return () => { + setEyeDropperState(null); + }; + }, [setEyeDropperState]); + return ( -