mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Set Trailing Cmma to (#525)
This commit is contained in:
parent
25202aec11
commit
ee68af0fd3
53 changed files with 352 additions and 350 deletions
|
@ -20,7 +20,7 @@ export const actionChangeViewBackgroundColor: Action = {
|
|||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const actionClearCanvas: Action = {
|
||||
|
@ -28,7 +28,7 @@ export const actionClearCanvas: Action = {
|
|||
perform: () => {
|
||||
return {
|
||||
elements: [],
|
||||
appState: getDefaultAppState()
|
||||
appState: getDefaultAppState(),
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ updateData, t }) => (
|
||||
|
@ -47,5 +47,5 @@ export const actionClearCanvas: Action = {
|
|||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
|
|
@ -6,10 +6,10 @@ export const actionDeleteSelected: Action = {
|
|||
name: "deleteSelectedElements",
|
||||
perform: elements => {
|
||||
return {
|
||||
elements: deleteSelectedElements(elements)
|
||||
elements: deleteSelectedElements(elements),
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.delete",
|
||||
contextMenuOrder: 3,
|
||||
keyTest: event => event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE
|
||||
keyTest: event => event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE,
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ export const actionChangeProjectName: Action = {
|
|||
value={appState.name || "Unnamed"}
|
||||
onChange={(name: string) => updateData(name)}
|
||||
/>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionChangeExportBackground: Action = {
|
||||
|
@ -34,7 +34,7 @@ export const actionChangeExportBackground: Action = {
|
|||
/>{" "}
|
||||
{t("labels.withBackground")}
|
||||
</label>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionSaveScene: Action = {
|
||||
|
@ -51,7 +51,7 @@ export const actionSaveScene: Action = {
|
|||
aria-label={t("buttons.save")}
|
||||
onClick={() => updateData(null)}
|
||||
/>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionLoadScene: Action = {
|
||||
|
@ -59,7 +59,7 @@ export const actionLoadScene: Action = {
|
|||
perform: (
|
||||
elements,
|
||||
appState,
|
||||
{ elements: loadedElements, appState: loadedAppState }
|
||||
{ elements: loadedElements, appState: loadedAppState },
|
||||
) => {
|
||||
return { elements: loadedElements, appState: loadedAppState };
|
||||
},
|
||||
|
@ -77,5 +77,5 @@ export const actionLoadScene: Action = {
|
|||
.catch(err => console.error(err));
|
||||
}}
|
||||
/>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ import { AppState } from "../../src/types";
|
|||
|
||||
const changeProperty = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
callback: (element: ExcalidrawElement) => ExcalidrawElement
|
||||
callback: (element: ExcalidrawElement) => ExcalidrawElement,
|
||||
) => {
|
||||
return elements.map(element => {
|
||||
if (element.isSelected) {
|
||||
|
@ -23,7 +23,7 @@ const getFormValue = function<T>(
|
|||
editingElement: AppState["editingElement"],
|
||||
elements: readonly ExcalidrawElement[],
|
||||
getAttribute: (element: ExcalidrawElement) => T,
|
||||
defaultValue?: T
|
||||
defaultValue?: T,
|
||||
): T | null {
|
||||
return (
|
||||
(editingElement && getAttribute(editingElement)) ??
|
||||
|
@ -40,9 +40,9 @@ export const actionChangeStrokeColor: Action = {
|
|||
elements: changeProperty(elements, el => ({
|
||||
...el,
|
||||
shape: null,
|
||||
strokeColor: value
|
||||
strokeColor: value,
|
||||
})),
|
||||
appState: { ...appState, currentItemStrokeColor: value }
|
||||
appState: { ...appState, currentItemStrokeColor: value },
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData, t }) => (
|
||||
|
@ -54,12 +54,12 @@ export const actionChangeStrokeColor: Action = {
|
|||
appState.editingElement,
|
||||
elements,
|
||||
element => element.strokeColor,
|
||||
appState.currentItemStrokeColor
|
||||
appState.currentItemStrokeColor,
|
||||
)}
|
||||
onChange={updateData}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionChangeBackgroundColor: Action = {
|
||||
|
@ -69,9 +69,9 @@ export const actionChangeBackgroundColor: Action = {
|
|||
elements: changeProperty(elements, el => ({
|
||||
...el,
|
||||
shape: null,
|
||||
backgroundColor: value
|
||||
backgroundColor: value,
|
||||
})),
|
||||
appState: { ...appState, currentItemBackgroundColor: value }
|
||||
appState: { ...appState, currentItemBackgroundColor: value },
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData, t }) => (
|
||||
|
@ -83,12 +83,12 @@ export const actionChangeBackgroundColor: Action = {
|
|||
appState.editingElement,
|
||||
elements,
|
||||
element => element.backgroundColor,
|
||||
appState.currentItemBackgroundColor
|
||||
appState.currentItemBackgroundColor,
|
||||
)}
|
||||
onChange={updateData}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionChangeFillStyle: Action = {
|
||||
|
@ -98,8 +98,8 @@ export const actionChangeFillStyle: Action = {
|
|||
elements: changeProperty(elements, el => ({
|
||||
...el,
|
||||
shape: null,
|
||||
fillStyle: value
|
||||
}))
|
||||
fillStyle: value,
|
||||
})),
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData, t }) => (
|
||||
|
@ -109,19 +109,19 @@ export const actionChangeFillStyle: Action = {
|
|||
options={[
|
||||
{ value: "solid", text: t("labels.solid") },
|
||||
{ value: "hachure", text: t("labels.hachure") },
|
||||
{ value: "cross-hatch", text: t("labels.crossHatch") }
|
||||
{ value: "cross-hatch", text: t("labels.crossHatch") },
|
||||
]}
|
||||
value={getFormValue(
|
||||
appState.editingElement,
|
||||
elements,
|
||||
element => element.fillStyle
|
||||
element => element.fillStyle,
|
||||
)}
|
||||
onChange={value => {
|
||||
updateData(value);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionChangeStrokeWidth: Action = {
|
||||
|
@ -131,8 +131,8 @@ export const actionChangeStrokeWidth: Action = {
|
|||
elements: changeProperty(elements, el => ({
|
||||
...el,
|
||||
shape: null,
|
||||
strokeWidth: value
|
||||
}))
|
||||
strokeWidth: value,
|
||||
})),
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData, t }) => (
|
||||
|
@ -142,17 +142,17 @@ export const actionChangeStrokeWidth: Action = {
|
|||
options={[
|
||||
{ value: 1, text: t("labels.thin") },
|
||||
{ value: 2, text: t("labels.bold") },
|
||||
{ value: 4, text: t("labels.extraBold") }
|
||||
{ value: 4, text: t("labels.extraBold") },
|
||||
]}
|
||||
value={getFormValue(
|
||||
appState.editingElement,
|
||||
elements,
|
||||
element => element.strokeWidth
|
||||
element => element.strokeWidth,
|
||||
)}
|
||||
onChange={value => updateData(value)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionChangeSloppiness: Action = {
|
||||
|
@ -162,8 +162,8 @@ export const actionChangeSloppiness: Action = {
|
|||
elements: changeProperty(elements, el => ({
|
||||
...el,
|
||||
shape: null,
|
||||
roughness: value
|
||||
}))
|
||||
roughness: value,
|
||||
})),
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData, t }) => (
|
||||
|
@ -173,17 +173,17 @@ export const actionChangeSloppiness: Action = {
|
|||
options={[
|
||||
{ value: 0, text: t("labels.architect") },
|
||||
{ value: 1, text: t("labels.artist") },
|
||||
{ value: 3, text: t("labels.cartoonist") }
|
||||
{ value: 3, text: t("labels.cartoonist") },
|
||||
]}
|
||||
value={getFormValue(
|
||||
appState.editingElement,
|
||||
elements,
|
||||
element => element.roughness
|
||||
element => element.roughness,
|
||||
)}
|
||||
onChange={value => updateData(value)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionChangeOpacity: Action = {
|
||||
|
@ -193,8 +193,8 @@ export const actionChangeOpacity: Action = {
|
|||
elements: changeProperty(elements, el => ({
|
||||
...el,
|
||||
shape: null,
|
||||
opacity: value
|
||||
}))
|
||||
opacity: value,
|
||||
})),
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData, t }) => (
|
||||
|
@ -210,12 +210,12 @@ export const actionChangeOpacity: Action = {
|
|||
appState.editingElement,
|
||||
elements,
|
||||
element => element.opacity,
|
||||
100 /* default opacity */
|
||||
100 /* default opacity */,
|
||||
) ?? undefined
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionChangeFontSize: Action = {
|
||||
|
@ -227,14 +227,14 @@ export const actionChangeFontSize: Action = {
|
|||
const element: ExcalidrawTextElement = {
|
||||
...el,
|
||||
shape: null,
|
||||
font: `${value}px ${el.font.split("px ")[1]}`
|
||||
font: `${value}px ${el.font.split("px ")[1]}`,
|
||||
};
|
||||
redrawTextBoundingBox(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
return el;
|
||||
})
|
||||
}),
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData, t }) => (
|
||||
|
@ -245,17 +245,17 @@ export const actionChangeFontSize: Action = {
|
|||
{ value: 16, text: t("labels.small") },
|
||||
{ value: 20, text: t("labels.medium") },
|
||||
{ value: 28, text: t("labels.large") },
|
||||
{ value: 36, text: t("labels.veryLarge") }
|
||||
{ value: 36, text: t("labels.veryLarge") },
|
||||
]}
|
||||
value={getFormValue(
|
||||
appState.editingElement,
|
||||
elements,
|
||||
element => isTextElement(element) && +element.font.split("px ")[0]
|
||||
element => isTextElement(element) && +element.font.split("px ")[0],
|
||||
)}
|
||||
onChange={value => updateData(value)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
export const actionChangeFontFamily: Action = {
|
||||
|
@ -267,14 +267,14 @@ export const actionChangeFontFamily: Action = {
|
|||
const element: ExcalidrawTextElement = {
|
||||
...el,
|
||||
shape: null,
|
||||
font: `${el.font.split("px ")[0]}px ${value}`
|
||||
font: `${el.font.split("px ")[0]}px ${value}`,
|
||||
};
|
||||
redrawTextBoundingBox(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
return el;
|
||||
})
|
||||
}),
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ elements, appState, updateData, t }) => (
|
||||
|
@ -284,15 +284,15 @@ export const actionChangeFontFamily: Action = {
|
|||
options={[
|
||||
{ value: "Virgil", text: t("labels.handDrawn") },
|
||||
{ value: "Helvetica", text: t("labels.normal") },
|
||||
{ value: "Cascadia", text: t("labels.code") }
|
||||
{ value: "Cascadia", text: t("labels.code") },
|
||||
]}
|
||||
value={getFormValue(
|
||||
appState.editingElement,
|
||||
elements,
|
||||
element => isTextElement(element) && element.font.split("px ")[1]
|
||||
element => isTextElement(element) && element.font.split("px ")[1],
|
||||
)}
|
||||
onChange={value => updateData(value)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
),
|
||||
};
|
||||
|
|
|
@ -5,9 +5,9 @@ export const actionSelectAll: Action = {
|
|||
name: "selectAll",
|
||||
perform: elements => {
|
||||
return {
|
||||
elements: elements.map(elem => ({ ...elem, isSelected: true }))
|
||||
elements: elements.map(elem => ({ ...elem, isSelected: true })),
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.selectAll",
|
||||
keyTest: event => event[KEYS.META] && event.code === "KeyA"
|
||||
keyTest: event => event[KEYS.META] && event.code === "KeyA",
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ export const actionCopyStyles: Action = {
|
|||
},
|
||||
contextItemLabel: "labels.copyStyles",
|
||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyC",
|
||||
contextMenuOrder: 0
|
||||
contextMenuOrder: 0,
|
||||
};
|
||||
|
||||
export const actionPasteStyles: Action = {
|
||||
|
@ -33,7 +33,7 @@ export const actionPasteStyles: Action = {
|
|||
strokeColor: pastedElement?.strokeColor,
|
||||
fillStyle: pastedElement?.fillStyle,
|
||||
opacity: pastedElement?.opacity,
|
||||
roughness: pastedElement?.roughness
|
||||
roughness: pastedElement?.roughness,
|
||||
};
|
||||
if (isTextElement(newElement)) {
|
||||
newElement.font = pastedElement?.font;
|
||||
|
@ -42,10 +42,10 @@ export const actionPasteStyles: Action = {
|
|||
return newElement;
|
||||
}
|
||||
return element;
|
||||
})
|
||||
}),
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.pasteStyles",
|
||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyV",
|
||||
contextMenuOrder: 1
|
||||
contextMenuOrder: 1,
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
moveOneLeft,
|
||||
moveOneRight,
|
||||
moveAllLeft,
|
||||
moveAllRight
|
||||
moveAllRight,
|
||||
} from "../zindex";
|
||||
import { getSelectedIndices } from "../scene";
|
||||
import { KEYS } from "../keys";
|
||||
|
@ -13,13 +13,13 @@ export const actionSendBackward: Action = {
|
|||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: moveOneLeft([...elements], getSelectedIndices(elements)),
|
||||
appState
|
||||
appState,
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.sendBackward",
|
||||
keyPriority: 40,
|
||||
keyTest: event =>
|
||||
event[KEYS.META] && event.shiftKey && event.altKey && event.code === "KeyB"
|
||||
event[KEYS.META] && event.shiftKey && event.altKey && event.code === "KeyB",
|
||||
};
|
||||
|
||||
export const actionBringForward: Action = {
|
||||
|
@ -27,13 +27,13 @@ export const actionBringForward: Action = {
|
|||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: moveOneRight([...elements], getSelectedIndices(elements)),
|
||||
appState
|
||||
appState,
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.bringForward",
|
||||
keyPriority: 40,
|
||||
keyTest: event =>
|
||||
event[KEYS.META] && event.shiftKey && event.altKey && event.code === "KeyF"
|
||||
event[KEYS.META] && event.shiftKey && event.altKey && event.code === "KeyF",
|
||||
};
|
||||
|
||||
export const actionSendToBack: Action = {
|
||||
|
@ -41,11 +41,11 @@ export const actionSendToBack: Action = {
|
|||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: moveAllLeft([...elements], getSelectedIndices(elements)),
|
||||
appState
|
||||
appState,
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.sendToBack",
|
||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyB"
|
||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyB",
|
||||
};
|
||||
|
||||
export const actionBringToFront: Action = {
|
||||
|
@ -53,9 +53,9 @@ export const actionBringToFront: Action = {
|
|||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: moveAllRight([...elements], getSelectedIndices(elements)),
|
||||
appState
|
||||
appState,
|
||||
};
|
||||
},
|
||||
contextItemLabel: "labels.bringToFront",
|
||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyF"
|
||||
keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyF",
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ export {
|
|||
actionBringForward,
|
||||
actionBringToFront,
|
||||
actionSendBackward,
|
||||
actionSendToBack
|
||||
actionSendToBack,
|
||||
} from "./actionZindex";
|
||||
export { actionSelectAll } from "./actionSelectAll";
|
||||
export {
|
||||
|
@ -15,19 +15,19 @@ export {
|
|||
actionChangeSloppiness,
|
||||
actionChangeOpacity,
|
||||
actionChangeFontSize,
|
||||
actionChangeFontFamily
|
||||
actionChangeFontFamily,
|
||||
} from "./actionProperties";
|
||||
|
||||
export {
|
||||
actionChangeViewBackgroundColor,
|
||||
actionClearCanvas
|
||||
actionClearCanvas,
|
||||
} from "./actionCanvas";
|
||||
|
||||
export {
|
||||
actionChangeProjectName,
|
||||
actionChangeExportBackground,
|
||||
actionSaveScene,
|
||||
actionLoadScene
|
||||
actionLoadScene,
|
||||
} from "./actionExport";
|
||||
|
||||
export { actionCopyStyles, actionPasteStyles } from "./actionStyles";
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
Action,
|
||||
ActionsManagerInterface,
|
||||
UpdaterFn,
|
||||
ActionFilterFn
|
||||
ActionFilterFn,
|
||||
} from "./types";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState } from "../types";
|
||||
|
@ -17,7 +17,7 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
| null = null;
|
||||
|
||||
setUpdater(
|
||||
updater: (elements: ExcalidrawElement[], appState: AppState) => void
|
||||
updater: (elements: ExcalidrawElement[], appState: AppState) => void,
|
||||
) {
|
||||
this.updater = updater;
|
||||
}
|
||||
|
@ -29,12 +29,12 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
handleKeyDown(
|
||||
event: KeyboardEvent,
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState
|
||||
appState: AppState,
|
||||
) {
|
||||
const data = Object.values(this.actions)
|
||||
.sort((a, b) => (b.keyPriority || 0) - (a.keyPriority || 0))
|
||||
.filter(
|
||||
action => action.keyTest && action.keyTest(event, elements, appState)
|
||||
action => action.keyTest && action.keyTest(event, elements, appState),
|
||||
);
|
||||
|
||||
if (data.length === 0) return {};
|
||||
|
@ -48,7 +48,7 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
appState: AppState,
|
||||
updater: UpdaterFn,
|
||||
actionFilter: ActionFilterFn = action => action,
|
||||
t?: TFunction
|
||||
t?: TFunction,
|
||||
) {
|
||||
return Object.values(this.actions)
|
||||
.filter(actionFilter)
|
||||
|
@ -56,7 +56,7 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
.sort(
|
||||
(a, b) =>
|
||||
(a.contextMenuOrder !== undefined ? a.contextMenuOrder : 999) -
|
||||
(b.contextMenuOrder !== undefined ? b.contextMenuOrder : 999)
|
||||
(b.contextMenuOrder !== undefined ? b.contextMenuOrder : 999),
|
||||
)
|
||||
.map(action => ({
|
||||
label:
|
||||
|
@ -65,7 +65,7 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
: action.contextItemLabel!,
|
||||
action: () => {
|
||||
updater(action.perform(elements, appState, null));
|
||||
}
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
updater: UpdaterFn,
|
||||
t: TFunction
|
||||
t: TFunction,
|
||||
) {
|
||||
if (this.actions[name] && "PanelComponent" in this.actions[name]) {
|
||||
const action = this.actions[name];
|
||||
|
|
|
@ -11,7 +11,7 @@ export type ActionResult = {
|
|||
type ActionFn = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
formData: any
|
||||
formData: any,
|
||||
) => ActionResult;
|
||||
|
||||
export type UpdaterFn = (res: ActionResult) => void;
|
||||
|
@ -30,7 +30,7 @@ export interface Action {
|
|||
keyTest?: (
|
||||
event: KeyboardEvent,
|
||||
elements?: readonly ExcalidrawElement[],
|
||||
appState?: AppState
|
||||
appState?: AppState,
|
||||
) => boolean;
|
||||
contextItemLabel?: string;
|
||||
contextMenuOrder?: number;
|
||||
|
@ -44,19 +44,19 @@ export interface ActionsManagerInterface {
|
|||
handleKeyDown: (
|
||||
event: KeyboardEvent,
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState
|
||||
appState: AppState,
|
||||
) => ActionResult | {};
|
||||
getContextMenuItems: (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
updater: UpdaterFn,
|
||||
actionFilter: ActionFilterFn
|
||||
actionFilter: ActionFilterFn,
|
||||
) => { label: string; action: () => void }[];
|
||||
renderAction: (
|
||||
name: string,
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
updater: UpdaterFn,
|
||||
t: TFunction
|
||||
t: TFunction,
|
||||
) => React.ReactElement | null;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue