Expose renderScrollbars to AppState

This commit is contained in:
Jack Walsh 2025-04-16 12:28:06 +10:00
parent 58f7d33d80
commit c1be250493
7 changed files with 32 additions and 1 deletions

View file

@ -31,6 +31,7 @@ All `props` are _optional_.
| [`generateIdForFile`](#generateidforfile) | `function` | \_ | Allows you to override `id` generation for files added on canvas |
| [`validateEmbeddable`](#validateembeddable) | `string[]` \| `boolean` \| `RegExp` \| `RegExp[]` \| <code>((link: string) => boolean &#124; 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>` |
| [`renderScrollbars`] | `boolean`| | `false` | Indicates whether scrollbars will be shown
### Storing custom data on Excalidraw elements

View file

@ -104,6 +104,7 @@ export default function ExampleApp({
const [viewModeEnabled, setViewModeEnabled] = useState(false);
const [zenModeEnabled, setZenModeEnabled] = useState(false);
const [gridModeEnabled, setGridModeEnabled] = useState(false);
const [renderScrollbars, setRenderScrollbars] = useState(false);
const [blobUrl, setBlobUrl] = useState<string>("");
const [canvasUrl, setCanvasUrl] = useState<string>("");
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
@ -192,6 +193,7 @@ export default function ExampleApp({
}) => setPointerData(payload),
viewModeEnabled,
zenModeEnabled,
renderScrollbars,
gridModeEnabled,
theme,
name: "Custom name of drawing",
@ -710,6 +712,14 @@ export default function ExampleApp({
/>
Grid mode
</label>
<label>
<input
type="checkbox"
checked={renderScrollbars}
onChange={() => setRenderScrollbars(!renderScrollbars)}
/>
Render scrollbars
</label>
<label>
<input
type="checkbox"

View file

@ -81,6 +81,7 @@ export const getDefaultAppState = (): Omit<
openDialog: null,
pasteDialog: { shown: false, data: null },
previousSelectedElementIds: {},
renderScrollbars: false,
resizingElement: null,
scrolledOutside: false,
scrollX: 0,
@ -208,6 +209,7 @@ const APP_STATE_STORAGE_CONF = (<
openDialog: { browser: false, export: false, server: false },
pasteDialog: { browser: false, export: false, server: false },
previousSelectedElementIds: { browser: true, export: false, server: false },
renderScrollbars: { browser: true, export: false, server: false },
resizingElement: { browser: false, export: false, server: false },
scrolledOutside: { browser: true, export: false, server: false },
scrollX: { browser: true, export: false, server: false },

View file

@ -721,6 +721,7 @@ class App extends React.Component<AppProps, AppState> {
zenModeEnabled = false,
gridModeEnabled = false,
objectsSnapModeEnabled = false,
renderScrollbars = false,
theme = defaultAppState.theme,
name = `${t("labels.untitled")}-${getDateTime()}`,
} = props;
@ -731,6 +732,7 @@ class App extends React.Component<AppProps, AppState> {
...this.getCanvasOffsets(),
viewModeEnabled,
zenModeEnabled,
renderScrollbars,
objectsSnapModeEnabled,
gridModeEnabled: gridModeEnabled ?? defaultAppState.gridModeEnabled,
name,
@ -2206,6 +2208,7 @@ class App extends React.Component<AppProps, AppState> {
if (actionResult.appState || editingTextElement || this.state.contextMenu) {
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
let renderScrollbars = actionResult?.appState?.renderScrollbars || false;
const theme =
actionResult?.appState?.theme || this.props.theme || THEME.LIGHT;
const name = actionResult?.appState?.name ?? this.state.name;
@ -2219,6 +2222,10 @@ class App extends React.Component<AppProps, AppState> {
zenModeEnabled = this.props.zenModeEnabled;
}
if (typeof this.props.renderScrollbars !== "undefined") {
renderScrollbars = this.props.renderScrollbars;
}
editingTextElement = actionResult.appState?.editingTextElement || null;
// make sure editingTextElement points to latest element reference
@ -2252,6 +2259,7 @@ class App extends React.Component<AppProps, AppState> {
editingTextElement,
viewModeEnabled,
zenModeEnabled,
renderScrollbars,
theme,
name,
errorMessage,
@ -2863,6 +2871,10 @@ class App extends React.Component<AppProps, AppState> {
this.setState({ theme: this.props.theme });
}
if (prevProps.renderScrollbars !== this.props.renderScrollbars) {
this.setState({ renderScrollbars: !!this.props.renderScrollbars });
}
this.excalidrawContainerRef.current?.classList.toggle(
"theme--dark",
this.state.theme === THEME.DARK,

View file

@ -143,7 +143,7 @@ const InteractiveCanvas = (props: InteractiveCanvasProps) => {
remotePointerUsernames,
remotePointerUserStates,
selectionColor,
renderScrollbars: false,
renderScrollbars: props.appState.renderScrollbars,
},
device: props.device,
callback: props.renderInteractiveSceneCallback,
@ -214,6 +214,7 @@ const getRelevantAppStateProps = (
isCropping: appState.isCropping,
croppingElementId: appState.croppingElementId,
searchMatches: appState.searchMatches,
renderScrollbars: appState.renderScrollbars,
});
const areEqual = (

View file

@ -53,6 +53,7 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
renderEmbeddable,
aiEnabled,
showDeprecatedFonts,
renderScrollbars,
} = props;
const canvasActions = props.UIOptions?.canvasActions;
@ -143,6 +144,7 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
renderEmbeddable={renderEmbeddable}
aiEnabled={aiEnabled !== false}
showDeprecatedFonts={showDeprecatedFonts}
renderScrollbars={renderScrollbars}
>
{children}
</App>

View file

@ -230,6 +230,7 @@ export type InteractiveCanvasAppState = Readonly<
croppingElementId: AppState["croppingElementId"];
// Search matches
searchMatches: AppState["searchMatches"];
renderScrollbars: AppState["renderScrollbars"];
}
>;
@ -428,6 +429,7 @@ export interface AppState {
croppingElementId: ExcalidrawElement["id"] | null;
searchMatches: readonly SearchMatch[];
renderScrollbars: boolean;
}
type SearchMatch = {
@ -601,6 +603,7 @@ export interface ExcalidrawProps {
) => JSX.Element | null;
aiEnabled?: boolean;
showDeprecatedFonts?: boolean;
renderScrollbars?: boolean;
}
export type SceneData = {