Skip to content

Commit

Permalink
Allow GraphiQL apps control over closing tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
klippx committed Mar 19, 2024
1 parent ece99f6 commit d600dbe
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
30 changes: 30 additions & 0 deletions packages/graphiql-react/src/editor/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ export type EditorContextType = TabsState & {
* @param index The index of the tab that should be switched to.
*/
changeTab(index: number): void;
/**
* When the user clicks a close tab button, this function is invoked with
* the index of the tab that is about to be closed. It returns a promise
* that should resolve to `true` (meaning the tab may be closed) or `false`
* (meaning the tab may not be closed).
* @param index The index of the tab that should be closed.
*/
closeTabConfirmation(index: number): Promise<boolean>;
/**
* Move a tab to a new spot.
* @param newOrder The new order for the tabs.
Expand Down Expand Up @@ -212,6 +220,14 @@ export type EditorContextProviderProps = {
* @param operationName The operation name after it has been changed.
*/
onEditOperationName?(operationName: string): void;
/**
* When the user clicks a close tab button, this function is invoked with
* the index of the tab that is about to be closed. It returns a promise
* that should resolve to `true` (meaning the tab may be closed) or `false`
* (meaning the tab may not be closed).
* @param index The index of the tab that should be closed.
*/
confirmCloseTab?(index: number): Promise<boolean>;
/**
* Invoked when the state of the tabs changes. Possible triggers are:
* - Updating any editor contents inside the currently active tab
Expand Down Expand Up @@ -422,6 +438,19 @@ export function EditorContextProvider(props: EditorContextProviderProps) {
[onTabChange, setEditorValues, storeTabs],
);

const closeTabConfirmation = useCallback<
EditorContextType['closeTabConfirmation']
>(
async index => {
if (props.confirmCloseTab) {
const confirmation = await props.confirmCloseTab(index);
return confirmation;
}
return true;
},
[props.confirmCloseTab],
);

const closeTab = useCallback<EditorContextType['closeTab']>(
index => {
setTabState(current => {
Expand Down Expand Up @@ -497,6 +526,7 @@ export function EditorContextProvider(props: EditorContextProviderProps) {
addTab,
changeTab,
moveTab,
closeTabConfirmation,
closeTab,
updateActiveTabValues,

Expand Down
2 changes: 2 additions & 0 deletions packages/graphiql-react/src/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type GraphiQLProviderProps = EditorContextProviderProps &

export function GraphiQLProvider({
children,
confirmCloseTab,
dangerouslyAssumeSchemaIsValid,
defaultQuery,
defaultHeaders,
Expand Down Expand Up @@ -53,6 +54,7 @@ export function GraphiQLProvider({
<StorageContextProvider storage={storage}>
<HistoryContextProvider maxHistoryLength={maxHistoryLength}>
<EditorContextProvider
confirmCloseTab={confirmCloseTab}
defaultQuery={defaultQuery}
defaultHeaders={defaultHeaders}
defaultTabs={defaultTabs}
Expand Down
14 changes: 10 additions & 4 deletions packages/graphiql/src/components/GraphiQL.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export type GraphiQLProps = Omit<GraphiQLProviderProps, 'children'> &

export function GraphiQL({
dangerouslyAssumeSchemaIsValid,
confirmCloseTab,
defaultQuery,
defaultTabs,
externalFragments,
Expand Down Expand Up @@ -138,6 +139,7 @@ export function GraphiQL({

return (
<GraphiQLProvider
confirmCloseTab={confirmCloseTab}
getDefaultFieldNames={getDefaultFieldNames}
dangerouslyAssumeSchemaIsValid={dangerouslyAssumeSchemaIsValid}
defaultQuery={defaultQuery}
Expand Down Expand Up @@ -545,11 +547,15 @@ export function GraphiQLInterface(props: GraphiQLInterfaceProps) {
{tab.title}
</Tab.Button>
<Tab.Close
onClick={() => {
if (editorContext.activeTabIndex === index) {
executionContext.stop();
onClick={async () => {
if (
await editorContext.closeTabConfirmation(index)
) {
if (editorContext.activeTabIndex === index) {
executionContext.stop();
}
editorContext.closeTab(index);
}
editorContext.closeTab(index);
}}
/>
</Tab>
Expand Down

0 comments on commit d600dbe

Please sign in to comment.