Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edit Post: Try displaying offline status through a useNetworkConnectivity() hook #59025

Draft
wants to merge 6 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions packages/compose/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,20 @@ _Returns_

- `import('react').RefCallback<TypeFromRef<TRef>>`: The merged ref callback.

### useNetworkConnectivity

Returns the current network connectivity status provided by `window.navigator`.

_Usage_

```jsx
const { isConnected } = useNetworkConnectivity();
```

_Returns_

- `NetworkInformation`: Network information.

### useObservableValue

React hook that lets you observe an entry in an `ObservableMap`. The hook returns the current value corresponding to the key, or `undefined` when there is no value stored. It also observes changes to the value and triggers an update of the calling component in case the value changes.
Expand Down
45 changes: 45 additions & 0 deletions packages/compose/src/hooks/use-network-connectivity/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* WordPress dependencies
*/
import { useEffect, useState } from '@wordpress/element';

/**
* @typedef {Object} NetworkInformation
*
* @property {boolean} [isConnected] Whether the device is connected to a network.
*/

/**
* Returns the current network connectivity status provided by `window.navigator`.
*
* @example
*
* ```jsx
* const { isConnected } = useNetworkConnectivity();
* ```
*
* @return {NetworkInformation} Network information.
*/
export default function useNetworkConnectivity() {
const [ isConnected, setIsConnected ] = useState( window.navigator.onLine );

const setOnline = () => {
setIsConnected( true );
};

const setOffline = () => {
setIsConnected( false );
};

useEffect( () => {
window.addEventListener( 'online', setOnline );
window.addEventListener( 'offline', setOffline );

return () => {
window.removeEventListener( 'online', setOnline );
window.removeEventListener( 'offline', setOffline );
};
}, [] );

return { isConnected };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* External dependencies
*/
import { renderHook } from '@testing-library/react';

/**
* Internal dependencies
*/
import useNetworkConnectivity from '../index';

describe( 'useNetworkConnectivity', () => {
describe( 'when network connectivity is available', () => {
beforeAll( () => {
jest.spyOn( window.navigator, 'onLine', 'get' ).mockReturnValue(
true
);
} );
it( 'should return true', () => {
const { result } = renderHook( () => useNetworkConnectivity() );

expect( result.current.isConnected ).toBe( true );
} );

it( 'should update the status when network connectivity changes', () => {
let { result } = renderHook( () => useNetworkConnectivity() );

expect( result.current.isConnected ).toBe( true );

jest.spyOn( window.navigator, 'onLine', 'get' ).mockReturnValue(
false
);

result = renderHook( () => useNetworkConnectivity() ).result;

expect( result.current.isConnected ).toBe( false );
} );
} );

describe( 'when network connectivity is unavailable', () => {
beforeAll( () => {
jest.spyOn( window.navigator, 'onLine', 'get' ).mockReturnValue(
false
);
} );
it( 'should return false', () => {
const { result } = renderHook( () => useNetworkConnectivity() );

expect( result.current.isConnected ).toBe( false );
} );

it( 'should update the status when network connectivity changes', () => {
let { result } = renderHook( () => useNetworkConnectivity() );

expect( result.current.isConnected ).toBe( false );

jest.spyOn( window.navigator, 'onLine', 'get' ).mockReturnValue(
true
);

result = renderHook( () => useNetworkConnectivity() ).result;

expect( result.current.isConnected ).toBe( true );
} );
} );
} );
1 change: 1 addition & 0 deletions packages/compose/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ export { default as __experimentalUseDropZone } from './hooks/use-drop-zone';
export { default as useFocusableIframe } from './hooks/use-focusable-iframe';
export { default as __experimentalUseFixedWindowList } from './hooks/use-fixed-window-list';
export { default as useObservableValue } from './hooks/use-observable-value';
export { default as useNetworkConnectivity } from './hooks/use-network-connectivity';
4 changes: 4 additions & 0 deletions packages/editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,10 @@ _Parameters_

> **Deprecated** since 5.3, use `wp.blockEditor.ObserveTyping` instead.

### OfflineStatus

Undocumented declaration.

### PageAttributesCheck

Wrapper component that renders its children only if the post type supports page attributes.
Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/components/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import PostPublishButtonOrToggle from '../post-publish-button/post-publish-butto
import PostSavedState from '../post-saved-state';
import PostViewLink from '../post-view-link';
import PreviewDropdown from '../preview-dropdown';
import OfflineStatus from '../offline-status';
import { store as editorStore } from '../../store';

const toolbarVariations = {
Expand Down Expand Up @@ -125,6 +126,7 @@ function Header( {
transition={ { type: 'tween' } }
className="editor-header__settings"
>
<OfflineStatus />
{ ! customSaveButton && ! isPublishSidebarOpened && (
// This button isn't completely hidden by the publish sidebar.
// We can't hide the whole toolbar when the publish sidebar is open because
Expand Down
1 change: 1 addition & 0 deletions packages/editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export { default as UnsavedChangesWarning } from './unsaved-changes-warning';
export { default as WordCount } from './word-count';
export { default as TimeToRead } from './time-to-read';
export { default as CharacterCount } from './character-count';
export { default as OfflineStatus } from './offline-status';

// State Related Components.
export { default as EditorProvider } from './provider';
Expand Down
32 changes: 32 additions & 0 deletions packages/editor/src/components/offline-status/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* WordPress dependencies
*/
import { useNetworkConnectivity, useViewportMatch } from '@wordpress/compose';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

const OfflineStatus = () => {
const { isConnected } = useNetworkConnectivity();
const isLargeViewport = useViewportMatch( 'small' );

if ( isConnected ) {
return null;
}

const label = isLargeViewport ? __( 'Working offline' ) : null;

return (
<Button
className="offline-status"
variant="tertiary"
size="compact"
icon="airplane"
label={ label }
aria-disabled
>
{ label }
</Button>
);
};

export default OfflineStatus;
Loading