mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: add props.renderScrollbars
(#9399)
* Expose renderScrollbars to AppState * fix: scrollbar rendering should use al renderable elements * remove `appState.renderScrollbars` * clean unused --------- Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
parent
b5d60973b7
commit
5fc13e4309
11 changed files with 53 additions and 16 deletions
|
@ -31,6 +31,7 @@ All `props` are _optional_.
|
||||||
| [`generateIdForFile`](#generateidforfile) | `function` | \_ | Allows you to override `id` generation for files added on canvas |
|
| [`generateIdForFile`](#generateidforfile) | `function` | \_ | Allows you to override `id` generation for files added on canvas |
|
||||||
| [`validateEmbeddable`](#validateembeddable) | `string[]` \| `boolean` \| `RegExp` \| `RegExp[]` \| <code>((link: string) => boolean | undefined)</code> | \_ | use for custom src url validation |
|
| [`validateEmbeddable`](#validateembeddable) | `string[]` \| `boolean` \| `RegExp` \| `RegExp[]` \| <code>((link: string) => boolean | undefined)</code> | \_ | use for custom src url validation |
|
||||||
| [`renderEmbeddable`](/docs/@excalidraw/excalidraw/api/props/render-props#renderEmbeddable) | `function` | \_ | Render function that can override the built-in `<iframe>` |
|
| [`renderEmbeddable`](/docs/@excalidraw/excalidraw/api/props/render-props#renderEmbeddable) | `function` | \_ | Render function that can override the built-in `<iframe>` |
|
||||||
|
| [`renderScrollbars`] | `boolean`| | `false` | Indicates whether scrollbars will be shown
|
||||||
|
|
||||||
### Storing custom data on Excalidraw elements
|
### Storing custom data on Excalidraw elements
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,7 @@ export default function ExampleApp({
|
||||||
const [viewModeEnabled, setViewModeEnabled] = useState(false);
|
const [viewModeEnabled, setViewModeEnabled] = useState(false);
|
||||||
const [zenModeEnabled, setZenModeEnabled] = useState(false);
|
const [zenModeEnabled, setZenModeEnabled] = useState(false);
|
||||||
const [gridModeEnabled, setGridModeEnabled] = useState(false);
|
const [gridModeEnabled, setGridModeEnabled] = useState(false);
|
||||||
|
const [renderScrollbars, setRenderScrollbars] = useState(false);
|
||||||
const [blobUrl, setBlobUrl] = useState<string>("");
|
const [blobUrl, setBlobUrl] = useState<string>("");
|
||||||
const [canvasUrl, setCanvasUrl] = useState<string>("");
|
const [canvasUrl, setCanvasUrl] = useState<string>("");
|
||||||
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
|
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
|
||||||
|
@ -192,6 +193,7 @@ export default function ExampleApp({
|
||||||
}) => setPointerData(payload),
|
}) => setPointerData(payload),
|
||||||
viewModeEnabled,
|
viewModeEnabled,
|
||||||
zenModeEnabled,
|
zenModeEnabled,
|
||||||
|
renderScrollbars,
|
||||||
gridModeEnabled,
|
gridModeEnabled,
|
||||||
theme,
|
theme,
|
||||||
name: "Custom name of drawing",
|
name: "Custom name of drawing",
|
||||||
|
@ -710,6 +712,14 @@ export default function ExampleApp({
|
||||||
/>
|
/>
|
||||||
Grid mode
|
Grid mode
|
||||||
</label>
|
</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={renderScrollbars}
|
||||||
|
onChange={() => setRenderScrollbars(!renderScrollbars)}
|
||||||
|
/>
|
||||||
|
Render scrollbars
|
||||||
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|
|
@ -1218,3 +1218,18 @@ export const elementCenterPoint = (
|
||||||
|
|
||||||
return pointFrom<GlobalPoint>(centerXPoint, centerYPoint);
|
return pointFrom<GlobalPoint>(centerXPoint, centerYPoint);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** hack for Array.isArray type guard not working with readonly value[] */
|
||||||
|
export const isReadonlyArray = (value?: any): value is readonly any[] => {
|
||||||
|
return Array.isArray(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sizeOf = (
|
||||||
|
value: readonly number[] | Readonly<Map<any, any>> | Record<any, any>,
|
||||||
|
): number => {
|
||||||
|
return isReadonlyArray(value)
|
||||||
|
? value.length
|
||||||
|
: value instanceof Map
|
||||||
|
? value.size
|
||||||
|
: Object.keys(value).length;
|
||||||
|
};
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import rough from "roughjs/bin/rough";
|
import rough from "roughjs/bin/rough";
|
||||||
|
|
||||||
import { rescalePoints, arrayToMap, invariant } from "@excalidraw/common";
|
import {
|
||||||
|
rescalePoints,
|
||||||
|
arrayToMap,
|
||||||
|
invariant,
|
||||||
|
sizeOf,
|
||||||
|
} from "@excalidraw/common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
degreesToRadians,
|
degreesToRadians,
|
||||||
|
@ -57,6 +62,7 @@ import type {
|
||||||
ElementsMap,
|
ElementsMap,
|
||||||
ExcalidrawRectanguloidElement,
|
ExcalidrawRectanguloidElement,
|
||||||
ExcalidrawEllipseElement,
|
ExcalidrawEllipseElement,
|
||||||
|
ElementsMapOrArray,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import type { Drawable, Op } from "roughjs/bin/core";
|
import type { Drawable, Op } from "roughjs/bin/core";
|
||||||
import type { Point as RoughPoint } from "roughjs/bin/geometry";
|
import type { Point as RoughPoint } from "roughjs/bin/geometry";
|
||||||
|
@ -938,10 +944,10 @@ export const getElementBounds = (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCommonBounds = (
|
export const getCommonBounds = (
|
||||||
elements: readonly ExcalidrawElement[],
|
elements: ElementsMapOrArray,
|
||||||
elementsMap?: ElementsMap,
|
elementsMap?: ElementsMap,
|
||||||
): Bounds => {
|
): Bounds => {
|
||||||
if (!elements.length) {
|
if (!sizeOf(elements)) {
|
||||||
return [0, 0, 0, 0];
|
return [0, 0, 0, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1830,6 +1830,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
}
|
}
|
||||||
scale={window.devicePixelRatio}
|
scale={window.devicePixelRatio}
|
||||||
appState={this.state}
|
appState={this.state}
|
||||||
|
renderScrollbars={
|
||||||
|
this.props.renderScrollbars === true
|
||||||
|
}
|
||||||
device={this.device}
|
device={this.device}
|
||||||
renderInteractiveSceneCallback={
|
renderInteractiveSceneCallback={
|
||||||
this.renderInteractiveSceneCallback
|
this.renderInteractiveSceneCallback
|
||||||
|
|
|
@ -34,6 +34,7 @@ type InteractiveCanvasProps = {
|
||||||
selectionNonce: number | undefined;
|
selectionNonce: number | undefined;
|
||||||
scale: number;
|
scale: number;
|
||||||
appState: InteractiveCanvasAppState;
|
appState: InteractiveCanvasAppState;
|
||||||
|
renderScrollbars: boolean;
|
||||||
device: Device;
|
device: Device;
|
||||||
renderInteractiveSceneCallback: (
|
renderInteractiveSceneCallback: (
|
||||||
data: RenderInteractiveSceneCallback,
|
data: RenderInteractiveSceneCallback,
|
||||||
|
@ -143,7 +144,7 @@ const InteractiveCanvas = (props: InteractiveCanvasProps) => {
|
||||||
remotePointerUsernames,
|
remotePointerUsernames,
|
||||||
remotePointerUserStates,
|
remotePointerUserStates,
|
||||||
selectionColor,
|
selectionColor,
|
||||||
renderScrollbars: false,
|
renderScrollbars: props.renderScrollbars,
|
||||||
},
|
},
|
||||||
device: props.device,
|
device: props.device,
|
||||||
callback: props.renderInteractiveSceneCallback,
|
callback: props.renderInteractiveSceneCallback,
|
||||||
|
@ -230,7 +231,8 @@ const areEqual = (
|
||||||
// on appState)
|
// on appState)
|
||||||
prevProps.elementsMap !== nextProps.elementsMap ||
|
prevProps.elementsMap !== nextProps.elementsMap ||
|
||||||
prevProps.visibleElements !== nextProps.visibleElements ||
|
prevProps.visibleElements !== nextProps.visibleElements ||
|
||||||
prevProps.selectedElements !== nextProps.selectedElements
|
prevProps.selectedElements !== nextProps.selectedElements ||
|
||||||
|
prevProps.renderScrollbars !== nextProps.renderScrollbars
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
||||||
renderEmbeddable,
|
renderEmbeddable,
|
||||||
aiEnabled,
|
aiEnabled,
|
||||||
showDeprecatedFonts,
|
showDeprecatedFonts,
|
||||||
|
renderScrollbars,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const canvasActions = props.UIOptions?.canvasActions;
|
const canvasActions = props.UIOptions?.canvasActions;
|
||||||
|
@ -143,6 +144,7 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
||||||
renderEmbeddable={renderEmbeddable}
|
renderEmbeddable={renderEmbeddable}
|
||||||
aiEnabled={aiEnabled !== false}
|
aiEnabled={aiEnabled !== false}
|
||||||
showDeprecatedFonts={showDeprecatedFonts}
|
showDeprecatedFonts={showDeprecatedFonts}
|
||||||
|
renderScrollbars={renderScrollbars}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</App>
|
</App>
|
||||||
|
|
|
@ -1182,7 +1182,7 @@ const _renderInteractiveScene = ({
|
||||||
let scrollBars;
|
let scrollBars;
|
||||||
if (renderConfig.renderScrollbars) {
|
if (renderConfig.renderScrollbars) {
|
||||||
scrollBars = getScrollBars(
|
scrollBars = getScrollBars(
|
||||||
visibleElements,
|
elementsMap,
|
||||||
normalizedWidth,
|
normalizedWidth,
|
||||||
normalizedHeight,
|
normalizedHeight,
|
||||||
appState,
|
appState,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
toBrandedType,
|
toBrandedType,
|
||||||
isDevEnv,
|
isDevEnv,
|
||||||
isTestEnv,
|
isTestEnv,
|
||||||
|
isReadonlyArray,
|
||||||
} from "@excalidraw/common";
|
} from "@excalidraw/common";
|
||||||
import { isNonDeletedElement } from "@excalidraw/element";
|
import { isNonDeletedElement } from "@excalidraw/element";
|
||||||
import { isFrameLikeElement } from "@excalidraw/element/typeChecks";
|
import { isFrameLikeElement } from "@excalidraw/element/typeChecks";
|
||||||
|
@ -292,9 +293,7 @@ class Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceAllElements(nextElements: ElementsMapOrArray) {
|
replaceAllElements(nextElements: ElementsMapOrArray) {
|
||||||
const _nextElements =
|
const _nextElements = isReadonlyArray(nextElements)
|
||||||
// ts doesn't like `Array.isArray` of `instanceof Map`
|
|
||||||
nextElements instanceof Array
|
|
||||||
? nextElements
|
? nextElements
|
||||||
: Array.from(nextElements.values());
|
: Array.from(nextElements.values());
|
||||||
const nextFrameLikes: ExcalidrawFrameLikeElement[] = [];
|
const nextFrameLikes: ExcalidrawFrameLikeElement[] = [];
|
||||||
|
|
|
@ -2,24 +2,22 @@ import { getGlobalCSSVariable } from "@excalidraw/common";
|
||||||
|
|
||||||
import { getCommonBounds } from "@excalidraw/element/bounds";
|
import { getCommonBounds } from "@excalidraw/element/bounds";
|
||||||
|
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
|
||||||
|
|
||||||
import { getLanguage } from "../i18n";
|
import { getLanguage } from "../i18n";
|
||||||
|
|
||||||
import type { InteractiveCanvasAppState } from "../types";
|
import type { InteractiveCanvasAppState } from "../types";
|
||||||
import type { ScrollBars } from "./types";
|
import type { RenderableElementsMap, ScrollBars } from "./types";
|
||||||
|
|
||||||
export const SCROLLBAR_MARGIN = 4;
|
export const SCROLLBAR_MARGIN = 4;
|
||||||
export const SCROLLBAR_WIDTH = 6;
|
export const SCROLLBAR_WIDTH = 6;
|
||||||
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
|
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
|
||||||
|
|
||||||
export const getScrollBars = (
|
export const getScrollBars = (
|
||||||
elements: readonly ExcalidrawElement[],
|
elements: RenderableElementsMap,
|
||||||
viewportWidth: number,
|
viewportWidth: number,
|
||||||
viewportHeight: number,
|
viewportHeight: number,
|
||||||
appState: InteractiveCanvasAppState,
|
appState: InteractiveCanvasAppState,
|
||||||
): ScrollBars => {
|
): ScrollBars => {
|
||||||
if (!elements.length) {
|
if (!elements.size) {
|
||||||
return {
|
return {
|
||||||
horizontal: null,
|
horizontal: null,
|
||||||
vertical: null,
|
vertical: null,
|
||||||
|
|
|
@ -601,6 +601,7 @@ export interface ExcalidrawProps {
|
||||||
) => JSX.Element | null;
|
) => JSX.Element | null;
|
||||||
aiEnabled?: boolean;
|
aiEnabled?: boolean;
|
||||||
showDeprecatedFonts?: boolean;
|
showDeprecatedFonts?: boolean;
|
||||||
|
renderScrollbars?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SceneData = {
|
export type SceneData = {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue