Commit e9dd0764 authored by Kyle Keating's avatar Kyle Keating Committed by Kyle Keating

Improve typechecking

- new-note-btn.js
- search-status-bar.js
- selection-tabs.js
- annotation-action-bar.js
- annotation-quote.js
parent e2c41192
......@@ -10,9 +10,10 @@ import { withServices } from '../util/service-context';
import AnnotationShareControl from './annotation-share-control';
import Button from './button';
/** @typedef {import("../../types/api").Annotation} Annotation */
/** @typedef {import('../../types/config').HostConfig} HostConfig */
/**
* @typedef {import("../../types/api").Annotation} Annotation
* @typedef {import('../../types/config').HostConfig} HostConfig
*/
/**
* @typedef AnnotationActionBarProps
......
......@@ -8,8 +8,22 @@ import { applyTheme } from '../util/theme';
import Excerpt from './excerpt';
/**
* @typedef {import('../../types/api').Annotation} Annotation
* @typedef {import('../../types/config').MergedConfig} MergedConfig
*/
/**
* @typedef AnnotationQuoteProps
* @prop {Annotation} annotation
* @prop {boolean} [isFocused] - Is this annotation currently focused?
* @prop {MergedConfig} [settings] - Used for theming.
*/
/**
* Display the selected text from the document associated with an annotation.
*
* @parm {AnnotationQuoteProps} props
*/
function AnnotationQuote({ annotation, isFocused, settings = {} }) {
// The language for the quote may be different than the client's UI (set by
......@@ -49,9 +63,7 @@ function AnnotationQuote({ annotation, isFocused, settings = {} }) {
AnnotationQuote.propTypes = {
annotation: propTypes.object.isRequired,
/** Is this annotation currently focused? */
isFocused: propTypes.bool,
// Used for theming.
settings: propTypes.object,
};
......
......@@ -8,6 +8,16 @@ import { applyTheme } from '../util/theme';
import Button from './button';
/**
* @typedef {import('../../types/config').MergedConfig} MergedConfig
*/
/**
* @typedef NewNoteButtonProps
* @prop {Object} annotationsService - Injected service.
* @prop {MergedConfig} settings - Injected service.
*/
function NewNoteButton({ annotationsService, settings }) {
const topLevelFrame = useStore(store => store.mainFrame());
const isLoggedIn = useStore(store => store.isLoggedIn());
......@@ -19,6 +29,9 @@ function NewNoteButton({ annotationsService, settings }) {
openSidebarPanel(uiConstants.PANEL_LOGIN_PROMPT);
return;
}
if (!topLevelFrame) {
return;
}
const annot = {
target: [],
uri: topLevelFrame.uri,
......@@ -39,7 +52,6 @@ function NewNoteButton({ annotationsService, settings }) {
);
}
NewNoteButton.propTypes = {
// Injected services.
annotationsService: propTypes.object.isRequired,
settings: propTypes.object.isRequired,
};
......
......@@ -108,7 +108,7 @@ function SearchStatusBar() {
// For non-user-focused modes, we can display the number of annotations
// that will be visible if the selection is cleared (`counts.annotations`)
// but this number is inaccurate/misleading when also focused on a user.
let selectedText;
let selectedText = '';
switch (selectedTab) {
case uiConstants.TAB_ORPHANS:
selectedText = 'Show all annotations and notes';
......
......@@ -10,7 +10,23 @@ import NewNoteBtn from './new-note-btn';
import SvgIcon from '../../shared/components/svg-icon';
/**
* Display name of the tab and annotation count.
* @typedef {import('../../types/config').MergedConfig} MergedConfig
*/
/**
* @typedef TabProps
* @prop {Object} children - Child components.
* @prop {number} count - The total annotations for this tab.
* @prop {boolean} isSelected - Is this tab currently selected?
* @prop {boolean} isWaitingToAnchor - Are there any annotations still waiting to anchor?
* @prop {string} label - A string label to use for `aria-label` and `title`
* @prop {() => any} onSelect - Callback to invoke when this tab is selected.
*/
/**
* Display name of the tab and annotation count.
*
* @param {TabProps} props
*/
function Tab({
children,
......@@ -40,7 +56,7 @@ function Tab({
onClick={selectTab}
onMouseDown={selectTab}
role="tab"
tabIndex="0"
tabIndex={0}
title={title}
aria-label={title}
aria-selected={isSelected.toString()}
......@@ -55,36 +71,25 @@ function Tab({
}
Tab.propTypes = {
/**
* Child components.
*/
children: propTypes.node.isRequired,
/**
* The total annotations for this tab.
*/
count: propTypes.number.isRequired,
/**
* Is this tab currently selected?
*/
isSelected: propTypes.bool.isRequired,
/**
* Are there any annotations still waiting to anchor?
*/
isWaitingToAnchor: propTypes.bool.isRequired,
/**
* A string label to use for `aria-label` and `title`
*/
label: propTypes.string.isRequired,
/**
* Callback to invoke when this tab is selected.
*/
onSelect: propTypes.func.isRequired,
};
/**
* Tabbed display of annotations and notes.
* @typedef SelectionTabsProps
* @prop {boolean} isLoading - Are we waiting on any annotations from the server?
* @prop {MergedConfig} settings - Injected service.
*/
/**
* Tabbed display of annotations and notes.
*
* @param {SelectionTabsProps} props
*/
function SelectionTabs({ isLoading, settings }) {
const selectedTab = useStore(store => store.getState().selection.selectedTab);
const noteCount = useStore(store => store.noteCount());
......@@ -176,12 +181,7 @@ function SelectionTabs({ isLoading, settings }) {
);
}
SelectionTabs.propTypes = {
/**
* Are we waiting on any annotations from the server?
*/
isLoading: propTypes.bool.isRequired,
// Injected services.
settings: propTypes.object.isRequired,
};
......
......@@ -57,7 +57,7 @@ describe('NewNoteButton', function () {
);
});
it('should display login prompt on click if user not logged in', () => {
it('should display login prompt on click if user is not logged in', () => {
fakeStore.isLoggedIn.returns(false);
const wrapper = createComponent();
......@@ -71,6 +71,17 @@ describe('NewNoteButton', function () {
);
});
it('should not add a new annotation if mainFrame() is null', () => {
fakeStore.mainFrame.returns(null);
fakeStore.isLoggedIn.returns(true);
const wrapper = createComponent();
act(() => {
wrapper.find('Button').props().onClick();
});
assert.notCalled(fakeAnnotationsService.create);
});
it('should add a new annotation to the store if user is logged in', () => {
fakeStore.isLoggedIn.returns(true);
fakeStore.mainFrame.returns({ uri: 'thisFrame' });
......
......@@ -163,7 +163,9 @@ const searchUris = createShallowEqualSelector(
* @prop {typeof updateFrameAnnotationFetchStatus} updateFrameAnnotationFetchStatus
*
* // Selectors
* // TODO add rest ...
* @prop {() => Frame[]} frames
* @prop {() => Frame|null} mainFrame
* @prop {() => string[]} searchUris
*/
export default {
......
......@@ -626,6 +626,10 @@ const threadState = createSelector(
* @prop {() => boolean} hasSelectedAnnotations
* @prop {() => string[]} selectedAnnotations
* @prop {() => string[]} sortKeys
*
* // Root Selectors
* @prop {() => ThreadState} threadState
*
*/
export default {
......
......@@ -43,7 +43,6 @@
// Remove them from this list as they are resolved.
"sidebar/components/hooks/use-root-thread.js",
"sidebar/components/annotation-header.js",
"sidebar/components/annotation-quote.js",
"sidebar/components/annotation-share-info.js",
"sidebar/components/annotation-viewer-content.js",
"sidebar/components/annotation.js",
......@@ -53,9 +52,6 @@
"sidebar/components/group-list.js",
"sidebar/components/help-panel.js",
"sidebar/components/hypothesis-app.js",
"sidebar/components/new-note-btn.js",
"sidebar/components/search-status-bar.js",
"sidebar/components/selection-tabs.js",
"sidebar/components/share-annotations-panel.js",
"sidebar/components/sidebar-content-error.js",
"sidebar/components/sidebar-content.js",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment