Compare commits

...

14 Commits

Author SHA1 Message Date
Arun Kumar
eb206cc932 Fix name input style in dark mode 2021-03-20 16:02:15 +05:30
Aakansha Doshi
16c287c848 Give preference to name prop when initialData.appState.name is present and update specs 2021-03-20 14:25:02 +05:30
Aakansha Doshi
78024873e5 no border and on hover no background change 2021-03-20 13:52:15 +05:30
Aakansha Doshi
4e41bd9dbb Merge remote-tracking branch 'origin/master' into updatescene-name 2021-03-20 13:43:01 +05:30
Aakansha Doshi
edc23b854f
minor fixes 2021-03-20 13:41:12 +05:30
Arun Kumar
4843c49556 remove eempty lines 2021-03-20 01:15:01 +05:30
Arun Kumar
d565413082 Add tests, update changelog and minor fixes 2021-03-20 01:07:49 +05:30
Aakansha Doshi
dcda7184d0 Merge remote-tracking branch 'origin/master' into updatescene-name 2021-03-20 00:24:24 +05:30
Arun Kumar
8d413670c8 Remove redundant if statement 2021-03-19 01:32:14 +05:30
Arun Kumar
f774452124 Remove customName from state 2021-03-19 01:30:27 +05:30
Arun Kumar
db4ed1ecb1 Make requested changes 2021-03-18 22:49:37 +05:30
Arun Kumar
489f45b910 Make requested changes 2021-03-18 16:36:12 +05:30
Arun Kumar
a17be085b0 Revert "Allow updating name on updateScene"
This reverts commit 4e07a608d38a585e0f3c04e26b9f5e0e404824b1.
2021-03-18 16:06:28 +05:30
Arun Kumar
4e07a608d3 Allow updating name on updateScene 2021-03-18 01:04:02 +05:30
13 changed files with 75 additions and 3 deletions

View File

@ -18,11 +18,12 @@ export const actionChangeProjectName = register({
trackEvent("change", "title"); trackEvent("change", "title");
return { appState: { ...appState, name: value }, commitToHistory: false }; return { appState: { ...appState, name: value }, commitToHistory: false };
}, },
PanelComponent: ({ appState, updateData }) => ( PanelComponent: ({ appState, updateData, appProps }) => (
<ProjectName <ProjectName
label={t("labels.fileTitle")} label={t("labels.fileTitle")}
value={appState.name || "Unnamed"} value={appState.name || "Unnamed"}
onChange={(name: string) => updateData(name)} onChange={(name: string) => updateData(name)}
isNameEditable={typeof appProps.name === "undefined"}
/> />
), ),
}); });

View File

@ -122,6 +122,7 @@ export class ActionManager implements ActionsManagerInterface {
appState={this.getAppState()} appState={this.getAppState()}
updateData={updateData} updateData={updateData}
id={id} id={id}
appProps={this.app.props}
/> />
); );
} }

View File

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import { ExcalidrawElement } from "../element/types"; import { ExcalidrawElement } from "../element/types";
import { AppState } from "../types"; import { AppState, ExcalidrawProps } from "../types";
/** if false, the action should be prevented */ /** if false, the action should be prevented */
export type ActionResult = export type ActionResult =
@ -94,6 +94,7 @@ export interface Action {
elements: readonly ExcalidrawElement[]; elements: readonly ExcalidrawElement[];
appState: AppState; appState: AppState;
updateData: (formData?: any) => void; updateData: (formData?: any) => void;
appProps: ExcalidrawProps;
id?: string; id?: string;
}>; }>;
perform: ActionFn; perform: ActionFn;

View File

@ -303,6 +303,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
zenModeEnabled = false, zenModeEnabled = false,
gridModeEnabled = false, gridModeEnabled = false,
theme = defaultAppState.theme, theme = defaultAppState.theme,
name = defaultAppState.name,
} = props; } = props;
this.state = { this.state = {
...defaultAppState, ...defaultAppState,
@ -314,6 +315,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
viewModeEnabled, viewModeEnabled,
zenModeEnabled, zenModeEnabled,
gridSize: gridModeEnabled ? GRID_SIZE : null, gridSize: gridModeEnabled ? GRID_SIZE : null,
name,
}; };
if (excalidrawRef) { if (excalidrawRef) {
const readyPromise = const readyPromise =
@ -523,6 +525,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false; let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
let gridSize = actionResult?.appState?.gridSize || null; let gridSize = actionResult?.appState?.gridSize || null;
let theme = actionResult?.appState?.theme || "light"; let theme = actionResult?.appState?.theme || "light";
let name = actionResult?.appState?.name || this.state.name;
if (typeof this.props.viewModeEnabled !== "undefined") { if (typeof this.props.viewModeEnabled !== "undefined") {
viewModeEnabled = this.props.viewModeEnabled; viewModeEnabled = this.props.viewModeEnabled;
@ -540,6 +543,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
theme = this.props.theme; theme = this.props.theme;
} }
if (typeof this.props.name !== "undefined") {
name = this.props.name;
}
this.setState( this.setState(
(state) => { (state) => {
// using Object.assign instead of spread to fool TS 4.2.2+ into // using Object.assign instead of spread to fool TS 4.2.2+ into
@ -556,6 +563,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
zenModeEnabled, zenModeEnabled,
gridSize, gridSize,
theme, theme,
name,
}); });
}, },
() => { () => {
@ -890,6 +898,13 @@ class App extends React.Component<ExcalidrawProps, AppState> {
gridSize: this.props.gridModeEnabled ? GRID_SIZE : null, gridSize: this.props.gridModeEnabled ? GRID_SIZE : null,
}); });
} }
if (this.props.name && prevProps.name !== this.props.name) {
this.setState({
name: this.props.name,
});
}
document document
.querySelector(".excalidraw") .querySelector(".excalidraw")
?.classList.toggle("theme--dark", this.state.theme === "dark"); ?.classList.toggle("theme--dark", this.state.theme === "dark");

View File

@ -34,6 +34,14 @@
.TextInput { .TextInput {
height: calc(1rem - 3px); height: calc(1rem - 3px);
&--readonly {
background: none;
border: none;
&:hover {
background: none;
}
}
} }
} }

View File

@ -257,6 +257,7 @@ export const ExportDialog = ({
onClick={() => { onClick={() => {
setModalIsShown(true); setModalIsShown(true);
}} }}
data-testid="export-button"
icon={exportFile} icon={exportFile}
type="button" type="button"
aria-label={t("buttons.export")} aria-label={t("buttons.export")}

View File

@ -7,6 +7,7 @@ type Props = {
value: string; value: string;
onChange: (value: string) => void; onChange: (value: string) => void;
label: string; label: string;
isNameEditable: boolean;
}; };
export class ProjectName extends Component<Props> { export class ProjectName extends Component<Props> {
@ -43,7 +44,7 @@ export class ProjectName extends Component<Props> {
}; };
public render() { public render() {
return ( return this.props.isNameEditable ? (
<span <span
suppressContentEditableWarning suppressContentEditableWarning
ref={this.makeEditable} ref={this.makeEditable}
@ -57,6 +58,13 @@ export class ProjectName extends Component<Props> {
> >
{this.props.value} {this.props.value}
</span> </span>
) : (
<span
className="TextInput TextInput--readonly"
aria-label={this.props.label}
>
{this.props.value}
</span>
); );
} }
} }

View File

@ -58,6 +58,7 @@ export const ToolButton = React.forwardRef((props: ToolButtonProps, ref) => {
"ToolIcon--selected": props.selected, "ToolIcon--selected": props.selected,
}, },
)} )}
data-testid={props["data-testid"]}
hidden={props.hidden} hidden={props.hidden}
title={props.title} title={props.title}
aria-label={props["aria-label"]} aria-label={props["aria-label"]}

View File

@ -18,6 +18,7 @@ Please add the latest change on the top under the correct section.
### Features ### Features
- Add `name` prop which indicates the name of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over `intialData.appState.name`, the `name` will be fully controlled by host app and the users won't be able to edit from within Excalidraw [#3273](https://github.com/excalidraw/excalidraw/pull/3273).
- Export API `setCanvasOffsets` via `ref` to set the offsets for Excalidraw[#3265](https://github.com/excalidraw/excalidraw/pull/3265). - Export API `setCanvasOffsets` via `ref` to set the offsets for Excalidraw[#3265](https://github.com/excalidraw/excalidraw/pull/3265).
#### BREAKING CHANGE #### BREAKING CHANGE
- `offsetLeft` and `offsetTop` props have been removed now so you have to use the `setCanvasOffsets` via `ref` to achieve the same. - `offsetLeft` and `offsetTop` props have been removed now so you have to use the `setCanvasOffsets` via `ref` to achieve the same.

View File

@ -376,6 +376,7 @@ export default function IndexPage() {
| [`gridModeEnabled`](#gridModeEnabled) | boolean | | This implies if the grid mode is enabled | | [`gridModeEnabled`](#gridModeEnabled) | boolean | | This implies if the grid mode is enabled |
| [`libraryReturnUrl`](#libraryReturnUrl) | string | | What URL should [libraries.excalidraw.com](https://libraries.excalidraw.com) be installed to | | [`libraryReturnUrl`](#libraryReturnUrl) | string | | What URL should [libraries.excalidraw.com](https://libraries.excalidraw.com) be installed to |
| [`theme`](#theme) | `light` or `dark` | | The theme of the Excalidraw component | | [`theme`](#theme) | `light` or `dark` | | The theme of the Excalidraw component |
| [`name`](#name) | string | | Name of the drawing |
#### `width` #### `width`
@ -534,6 +535,10 @@ If supplied, this URL will be used when user tries to install a library from [li
This prop controls Excalidraw's theme. When supplied, the value takes precedence over `intialData.appState.theme`, the theme will be fully controlled by the host app, and users won't be able to toggle it from within the app. This prop controls Excalidraw's theme. When supplied, the value takes precedence over `intialData.appState.theme`, the theme will be fully controlled by the host app, and users won't be able to toggle it from within the app.
### `name`
This prop sets the name of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over `intialData.appState.name`, the `name` will be fully controlled by host app and the users won't be able to edit from within Excalidraw.
### Extra API's ### Extra API's
#### `getSceneVersion` #### `getSceneVersion`

View File

@ -29,6 +29,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
gridModeEnabled, gridModeEnabled,
libraryReturnUrl, libraryReturnUrl,
theme, theme,
name,
} = props; } = props;
useEffect(() => { useEffect(() => {
@ -69,6 +70,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
gridModeEnabled={gridModeEnabled} gridModeEnabled={gridModeEnabled}
libraryReturnUrl={libraryReturnUrl} libraryReturnUrl={libraryReturnUrl}
theme={theme} theme={theme}
name={name}
/> />
</IsMobileProvider> </IsMobileProvider>
</InitializeApp> </InitializeApp>

View File

@ -3,6 +3,7 @@ import { fireEvent, GlobalTestState, render } from "./test-utils";
import Excalidraw from "../packages/excalidraw/index"; import Excalidraw from "../packages/excalidraw/index";
import { queryByText, queryByTestId } from "@testing-library/react"; import { queryByText, queryByTestId } from "@testing-library/react";
import { GRID_SIZE } from "../constants"; import { GRID_SIZE } from "../constants";
import { t } from "../i18n";
const { h } = window; const { h } = window;
@ -104,4 +105,30 @@ describe("<Excalidraw/>", () => {
expect(queryByTestId(container, "toggle-dark-mode")).toBe(null); expect(queryByTestId(container, "toggle-dark-mode")).toBe(null);
}); });
}); });
describe("Test name prop", () => {
it('should allow editing name when the name prop is "undefined"', async () => {
const { container } = await render(<Excalidraw />);
fireEvent.click(queryByTestId(container, "export-button")!);
const textInput = document.querySelector(
".ExportDialog__name .TextInput",
);
expect(textInput?.textContent).toContain(`${t("labels.untitled")}`);
expect(textInput?.hasAttribute("data-type")).toBe(true);
});
it('should set the name and not allow editing when the name prop is present"', async () => {
const name = "test";
const { container } = await render(<Excalidraw name={name} />);
await fireEvent.click(queryByTestId(container, "export-button")!);
const textInput = document.querySelector(
".ExportDialog__name .TextInput",
);
expect(textInput?.textContent).toEqual(name);
expect(textInput?.hasAttribute("data-type")).toBe(false);
});
});
}); });

View File

@ -187,6 +187,7 @@ export interface ExcalidrawProps {
gridModeEnabled?: boolean; gridModeEnabled?: boolean;
libraryReturnUrl?: string; libraryReturnUrl?: string;
theme?: "dark" | "light"; theme?: "dark" | "light";
name?: string;
} }
export type SceneData = { export type SceneData = {