mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Merge remote-tracking branch 'origin/release' into danieljgeiger-mathjax
This commit is contained in:
commit
e4ddd08bb1
261 changed files with 12625 additions and 14661 deletions
16
src/packages/excalidraw/.size-limit.json
Normal file
16
src/packages/excalidraw/.size-limit.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"path": "dist/excalidraw.production.min.js",
|
||||
"limit": "290 kB"
|
||||
},
|
||||
{
|
||||
"path": "dist/excalidraw-assets/locales",
|
||||
"name": "dist/excalidraw-assets/locales",
|
||||
"limit": "270 kB"
|
||||
},
|
||||
{
|
||||
"path": "dist/excalidraw-assets/vendor-*.js",
|
||||
"name": "dist/excalidraw-assets/vendor*.js",
|
||||
"limit": "30 kB"
|
||||
}
|
||||
]
|
|
@ -13,8 +13,29 @@ Please add the latest change on the top under the correct section.
|
|||
|
||||
## Unreleased
|
||||
|
||||
### renderEmbeddable
|
||||
|
||||
```tsx
|
||||
(element: NonDeletedExcalidrawElement, radius: number, appState: UIAppState) => JSX.Element | null;`
|
||||
```
|
||||
|
||||
The renderEmbeddable function allows you to customize the rendering of a JSX component instead of using the default `<iframe>`. By setting props.renderEmbeddable, you can provide a custom implementation for rendering the element.
|
||||
|
||||
#### Parameters:
|
||||
|
||||
- element (NonDeletedExcalidrawElement): The element to be rendered.
|
||||
- radius (number): The calculated border radius in pixels.
|
||||
- appState (UIAppState): The current state of the UI.
|
||||
|
||||
#### Return value:
|
||||
|
||||
JSX.Element | null: The JSX component representing the custom rendering, or null if the default `<iframe>` should be rendered.
|
||||
|
||||
### Features
|
||||
|
||||
- Added [`props.validateEmbeddable`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props#validateEmbeddable) to customize embeddable src url validation. [#6691](https://github.com/excalidraw/excalidraw/pull/6691)
|
||||
- Add support for `opts.fitToViewport` and `opts.viewportZoomFactor` in the [`ExcalidrawAPI.scrollToContent`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/ref#scrolltocontent) API. [#6581](https://github.com/excalidraw/excalidraw/pull/6581).
|
||||
- Properly sanitize element `link` urls. [#6728](https://github.com/excalidraw/excalidraw/pull/6728).
|
||||
- Sidebar component now supports tabs — for more detailed description of new behavior and breaking changes, see the linked PR. [#6213](https://github.com/excalidraw/excalidraw/pull/6213)
|
||||
- Exposed `DefaultSidebar` component to allow modifying the default sidebar, such as adding custom tabs to it. [#6213](https://github.com/excalidraw/excalidraw/pull/6213)
|
||||
|
||||
|
@ -63,7 +84,7 @@ Please add the latest change on the top under the correct section.
|
|||
|
||||
### Features
|
||||
|
||||
- [`ExcalidrawAPI.scrolToContent`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/ref#scrolltocontent) has new opts object allowing you to fit viewport to content, and animate the scrolling. [#6319](https://github.com/excalidraw/excalidraw/pull/6319)
|
||||
- [`ExcalidrawAPI.scrollToContent`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/ref#scrolltocontent) has new opts object allowing you to fit viewport to content, and animate the scrolling. [#6319](https://github.com/excalidraw/excalidraw/pull/6319)
|
||||
|
||||
- Expose `useI18n()` hook return an object containing `t()` i18n helper and current `langCode`. You can use this in components you render as `<Excalidraw>` children to render any of our i18n locale strings. [#6224](https://github.com/excalidraw/excalidraw/pull/6224)
|
||||
|
||||
|
|
|
@ -43,3 +43,7 @@ Head over to the [docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/
|
|||
## API
|
||||
|
||||
Head over to the [docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api)
|
||||
|
||||
## Contributing
|
||||
|
||||
Head over to the [docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/contributing)
|
||||
|
|
|
@ -9,9 +9,9 @@ const parseEnvVariables = (filepath) => {
|
|||
},
|
||||
{},
|
||||
);
|
||||
envVars.PKG_NAME = JSON.stringify(pkg.name);
|
||||
envVars.PKG_VERSION = JSON.stringify(pkg.version);
|
||||
envVars.IS_EXCALIDRAW_NPM_PACKAGE = JSON.stringify(true);
|
||||
envVars.VITE_PKG_NAME = JSON.stringify(pkg.name);
|
||||
envVars.VITE_PKG_VERSION = JSON.stringify(pkg.version);
|
||||
envVars.VITE_IS_EXCALIDRAW_NPM_PACKAGE = JSON.stringify(true);
|
||||
return envVars;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import {
|
|||
LibraryItems,
|
||||
PointerDownState as ExcalidrawPointerDownState,
|
||||
} from "../../../types";
|
||||
import { NonDeletedExcalidrawElement } from "../../../element/types";
|
||||
import { NonDeletedExcalidrawElement, Theme } from "../../../element/types";
|
||||
import { ImportedLibraryData } from "../../../data/types";
|
||||
import CustomFooter from "./CustomFooter";
|
||||
import MobileFooter from "./MobileFooter";
|
||||
|
@ -96,7 +96,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
|
|||
const [canvasUrl, setCanvasUrl] = useState<string>("");
|
||||
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
|
||||
const [exportEmbedScene, setExportEmbedScene] = useState(false);
|
||||
const [theme, setTheme] = useState("light");
|
||||
const [theme, setTheme] = useState<Theme>("light");
|
||||
const [isCollaborating, setIsCollaborating] = useState(false);
|
||||
const [commentIcons, setCommentIcons] = useState<{ [id: string]: Comment }>(
|
||||
{},
|
||||
|
@ -595,11 +595,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
|
|||
type="checkbox"
|
||||
checked={theme === "dark"}
|
||||
onChange={() => {
|
||||
let newTheme = "light";
|
||||
if (theme === "light") {
|
||||
newTheme = "dark";
|
||||
}
|
||||
setTheme(newTheme);
|
||||
setTheme(theme === "light" ? "dark" : "light");
|
||||
}}
|
||||
/>
|
||||
Switch to Dark Theme
|
||||
|
@ -678,11 +674,17 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
|
|||
gridModeEnabled={gridModeEnabled}
|
||||
theme={theme}
|
||||
name="Custom name of drawing"
|
||||
UIOptions={{ canvasActions: { loadScene: false } }}
|
||||
UIOptions={{
|
||||
canvasActions: {
|
||||
loadScene: false,
|
||||
},
|
||||
}}
|
||||
renderTopRightUI={renderTopRightUI}
|
||||
onLinkOpen={onLinkOpen}
|
||||
onPointerDown={onPointerDown}
|
||||
onScrollChange={rerenderCommentIcons}
|
||||
// allow all urls
|
||||
validateEmbeddable={true}
|
||||
>
|
||||
{excalidrawAPI && (
|
||||
<Footer>
|
||||
|
@ -784,7 +786,6 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
|
|||
<div className="export export-blob">
|
||||
<img src={blobUrl} alt="" />
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={async () => {
|
||||
if (!excalidrawAPI) {
|
||||
|
@ -806,6 +807,78 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
|
|||
>
|
||||
Export to Canvas
|
||||
</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
if (!excalidrawAPI) {
|
||||
return;
|
||||
}
|
||||
const canvas = await exportToCanvas({
|
||||
elements: excalidrawAPI.getSceneElements(),
|
||||
appState: {
|
||||
...initialData.appState,
|
||||
exportWithDarkMode,
|
||||
},
|
||||
files: excalidrawAPI.getFiles(),
|
||||
});
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.font = "30px Virgil";
|
||||
ctx.strokeText("My custom text", 50, 60);
|
||||
setCanvasUrl(canvas.toDataURL());
|
||||
}}
|
||||
>
|
||||
Export to Canvas
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (!excalidrawAPI) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elements = excalidrawAPI.getSceneElements();
|
||||
excalidrawAPI.scrollToContent(elements[0], {
|
||||
fitToViewport: true,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Fit to viewport, first element
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (!excalidrawAPI) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elements = excalidrawAPI.getSceneElements();
|
||||
excalidrawAPI.scrollToContent(elements[0], {
|
||||
fitToContent: true,
|
||||
});
|
||||
|
||||
excalidrawAPI.scrollToContent(elements[0], {
|
||||
fitToContent: true,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Fit to content, first element
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (!excalidrawAPI) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elements = excalidrawAPI.getSceneElements();
|
||||
excalidrawAPI.scrollToContent(elements[0], {
|
||||
fitToContent: true,
|
||||
});
|
||||
|
||||
excalidrawAPI.scrollToContent(elements[0]);
|
||||
}}
|
||||
>
|
||||
Scroll to first element, no fitToContent, no fitToViewport
|
||||
</button>
|
||||
<div className="export export-canvas">
|
||||
<img src={canvasUrl} alt="" />
|
||||
</div>
|
||||
|
|
|
@ -42,6 +42,8 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
|||
onPointerDown,
|
||||
onScrollChange,
|
||||
children,
|
||||
validateEmbeddable,
|
||||
renderEmbeddable,
|
||||
} = props;
|
||||
|
||||
const canvasActions = props.UIOptions?.canvasActions;
|
||||
|
@ -115,6 +117,8 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
|||
onLinkOpen={onLinkOpen}
|
||||
onPointerDown={onPointerDown}
|
||||
onScrollChange={onScrollChange}
|
||||
validateEmbeddable={validateEmbeddable}
|
||||
renderEmbeddable={renderEmbeddable}
|
||||
>
|
||||
{children}
|
||||
</App>
|
||||
|
@ -247,3 +251,5 @@ export { WelcomeScreen };
|
|||
export { LiveCollaborationTrigger };
|
||||
|
||||
export { DefaultSidebar } from "../../components/DefaultSidebar";
|
||||
|
||||
export { normalizeLink } from "../../data/url";
|
||||
|
|
|
@ -52,15 +52,19 @@
|
|||
"@babel/preset-env": "7.18.6",
|
||||
"@babel/preset-react": "7.18.6",
|
||||
"@babel/preset-typescript": "7.18.6",
|
||||
"@size-limit/preset-big-lib": "8.2.6",
|
||||
"autoprefixer": "10.4.7",
|
||||
"babel-loader": "8.2.5",
|
||||
"babel-plugin-transform-class-properties": "6.24.1",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "6.7.1",
|
||||
"dotenv": "16.0.1",
|
||||
"import-meta-loader": "1.1.0",
|
||||
"mini-css-extract-plugin": "2.6.1",
|
||||
"postcss-loader": "7.0.1",
|
||||
"sass-loader": "13.0.2",
|
||||
"size-limit": "8.2.4",
|
||||
"style-loader": "3.3.3",
|
||||
"terser-webpack-plugin": "5.3.3",
|
||||
"ts-loader": "9.3.1",
|
||||
"typescript": "4.9.4",
|
||||
|
@ -79,6 +83,7 @@
|
|||
"pack": "yarn build:umd && yarn pack",
|
||||
"start": "webpack serve --config webpack.dev-server.config.js",
|
||||
"install:deps": "yarn install --frozen-lockfile && yarn --cwd ../../../",
|
||||
"build:example": "EXAMPLE=true webpack --config webpack.dev-server.config.js && yarn gen:types"
|
||||
"build:example": "EXAMPLE=true webpack --config webpack.dev-server.config.js && yarn gen:types",
|
||||
"size": "yarn build:umd && size-limit"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ if (process.env.NODE_ENV !== ENV.TEST) {
|
|||
}
|
||||
__webpack_public_path__ =
|
||||
window.EXCALIDRAW_ASSET_PATH ||
|
||||
`https://unpkg.com/${process.env.PKG_NAME}@${process.env.PKG_VERSION}/dist/`;
|
||||
`https://unpkg.com/${process.env.VITE_PKG_NAME}@${process.env.VITE_PKG_VERSION}/dist/`;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ module.exports = {
|
|||
exclude:
|
||||
/node_modules\/(?!(browser-fs-access|canvas-roundrect-polyfill))/,
|
||||
use: [
|
||||
{
|
||||
loader: "import-meta-loader",
|
||||
},
|
||||
{
|
||||
loader: "ts-loader",
|
||||
options: {
|
||||
|
|
|
@ -50,6 +50,9 @@ module.exports = {
|
|||
/node_modules\/(?!(browser-fs-access|canvas-roundrect-polyfill))/,
|
||||
|
||||
use: [
|
||||
{
|
||||
loader: "import-meta-loader",
|
||||
},
|
||||
{
|
||||
loader: "ts-loader",
|
||||
options: {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -178,8 +178,10 @@ export const exportToSvg = async ({
|
|||
appState = getDefaultAppState(),
|
||||
files = {},
|
||||
exportPadding,
|
||||
renderEmbeddables,
|
||||
}: Omit<ExportOpts, "getDimensions"> & {
|
||||
exportPadding?: number;
|
||||
renderEmbeddables?: boolean;
|
||||
}): Promise<SVGSVGElement> => {
|
||||
const { elements: restoredElements, appState: restoredAppState } = restore(
|
||||
{ elements, appState },
|
||||
|
@ -197,6 +199,7 @@ export const exportToSvg = async ({
|
|||
exportAppState,
|
||||
files,
|
||||
{
|
||||
renderEmbeddables,
|
||||
// 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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue