Commit 5f82322e authored by Robert Knight's avatar Robert Knight

Add missing types to various callbacks / props in components

parent 6986607d
...@@ -116,6 +116,7 @@ function AnnotationEditor({ ...@@ -116,6 +116,7 @@ function AnnotationEditor({
}; };
// Allow saving of annotation by pressing CMD/CTRL-Enter // Allow saving of annotation by pressing CMD/CTRL-Enter
/** @param {KeyboardEvent} event */
const onKeyDown = event => { const onKeyDown = event => {
const key = normalizeKeyName(event.key); const key = normalizeKeyName(event.key);
if (isEmpty) { if (isEmpty) {
......
...@@ -10,7 +10,7 @@ import { applyTheme } from '../helpers/theme'; ...@@ -10,7 +10,7 @@ import { applyTheme } from '../helpers/theme';
* @typedef InlineControlsProps * @typedef InlineControlsProps
* @prop {boolean} isCollapsed * @prop {boolean} isCollapsed
* @prop {(collapsed: boolean) => any} setCollapsed * @prop {(collapsed: boolean) => any} setCollapsed
* @prop {object} [linkStyle] * @prop {Record<string, string>} [linkStyle]
*/ */
/** /**
...@@ -120,12 +120,13 @@ function Excerpt({ ...@@ -120,12 +120,13 @@ function Excerpt({
const isCollapsed = inlineControls ? collapsedByInlineControls : collapse; const isCollapsed = inlineControls ? collapsedByInlineControls : collapse;
const isExpandable = isOverflowing && isCollapsed; const isExpandable = isOverflowing && isCollapsed;
/** @type {object} */ /** @type {Record<string, number>} */
const contentStyle = {}; const contentStyle = {};
if (contentHeight !== 0) { if (contentHeight !== 0) {
contentStyle['max-height'] = isExpandable ? collapsedHeight : contentHeight; contentStyle['max-height'] = isExpandable ? collapsedHeight : contentHeight;
} }
/** @param {boolean} collapsed */
const setCollapsed = collapsed => const setCollapsed = collapsed =>
inlineControls inlineControls
? setCollapsedByInlineControls(collapsed) ? setCollapsedByInlineControls(collapsed)
......
...@@ -74,8 +74,15 @@ function HelpPanel({ auth, session }) { ...@@ -74,8 +74,15 @@ function HelpPanel({ auth, session }) {
const hasAutoDisplayPreference = const hasAutoDisplayPreference =
!!store.profile().preferences.show_sidebar_tutorial; !!store.profile().preferences.show_sidebar_tutorial;
const subPanelTitles = {
tutorial: 'Getting started',
versionInfo: 'About this version',
};
// The "Tutorial" (getting started) subpanel is the default panel shown // The "Tutorial" (getting started) subpanel is the default panel shown
const [activeSubPanel, setActiveSubPanel] = useState('tutorial'); const [activeSubPanel, setActiveSubPanel] = useState(
/** @type {keyof subPanelTitles} */ ('tutorial')
);
// Build version details about this session/app // Build version details about this session/app
const versionData = useMemo(() => { const versionData = useMemo(() => {
...@@ -100,17 +107,17 @@ function HelpPanel({ auth, session }) { ...@@ -100,17 +107,17 @@ function HelpPanel({ auth, session }) {
// create-new-ticket form // create-new-ticket form
const supportTicketURL = `https://web.hypothes.is/get-help/?sys_info=${versionData.asEncodedURLString()}`; const supportTicketURL = `https://web.hypothes.is/get-help/?sys_info=${versionData.asEncodedURLString()}`;
const subPanelTitles = { /**
tutorial: 'Getting started', * @param {Event} e
versionInfo: 'About this version', * @param {keyof subPanelTitles} panelName
}; */
const openSubPanel = (e, panelName) => { const openSubPanel = (e, panelName) => {
e.preventDefault(); e.preventDefault();
setActiveSubPanel(panelName); setActiveSubPanel(panelName);
}; };
const onActiveChanged = useCallback( const onActiveChanged = useCallback(
/** @param {boolean} active */
active => { active => {
if (!active && hasAutoDisplayPreference) { if (!active && hasAutoDisplayPreference) {
// If the tutorial is currently being auto-displayed, update the user // If the tutorial is currently being auto-displayed, update the user
......
...@@ -213,6 +213,8 @@ function Toolbar({ isPreviewing, onCommand, onTogglePreview }) { ...@@ -213,6 +213,8 @@ function Toolbar({ isPreviewing, onCommand, onTogglePreview }) {
/** /**
* Handles left and right arrow navigation as well as home and end * Handles left and right arrow navigation as well as home and end
* keys so the user may navigate the toolbar without multiple tab stops. * keys so the user may navigate the toolbar without multiple tab stops.
*
* @param {KeyboardEvent} e
*/ */
const handleKeyDown = e => { const handleKeyDown = e => {
let lowerLimit = 0; let lowerLimit = 0;
......
...@@ -116,6 +116,7 @@ export default function Menu({ ...@@ -116,6 +116,7 @@ export default function Menu({
// Toggle menu when user presses toggle button. The menu is shown on mouse // Toggle menu when user presses toggle button. The menu is shown on mouse
// press for a more responsive/native feel but also handles a click event for // press for a more responsive/native feel but also handles a click event for
// activation via other input methods. // activation via other input methods.
/** @param {Event} event */
const toggleMenu = event => { const toggleMenu = event => {
// If the menu was opened on press, don't close it again on the subsequent // If the menu was opened on press, don't close it again on the subsequent
// mouse up ("click") event. // mouse up ("click") event.
...@@ -144,9 +145,11 @@ export default function Menu({ ...@@ -144,9 +145,11 @@ export default function Menu({
// are user interactions outside of it (e.g. clicks) in the document // are user interactions outside of it (e.g. clicks) in the document
useElementShouldClose(menuRef, isOpen, closeMenu); useElementShouldClose(menuRef, isOpen, closeMenu);
/** @param {Event} e */
const stopPropagation = e => e.stopPropagation(); const stopPropagation = e => e.stopPropagation();
// It should also close if the user presses a key which activates menu items. // It should also close if the user presses a key which activates menu items.
/** @param {KeyboardEvent} event */
const handleMenuKeyDown = event => { const handleMenuKeyDown = event => {
const key = normalizeKeyName(event.key); const key = normalizeKeyName(event.key);
if (key === 'Enter' || key === ' ') { if (key === 'Enter' || key === ' ') {
......
...@@ -110,6 +110,7 @@ export default function MenuItem({ ...@@ -110,6 +110,7 @@ export default function MenuItem({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
/** @param {Event} event */
const onCloseSubmenu = event => { const onCloseSubmenu = event => {
if (onToggleSubmenu) { if (onToggleSubmenu) {
onToggleSubmenu(event); onToggleSubmenu(event);
...@@ -120,6 +121,7 @@ export default function MenuItem({ ...@@ -120,6 +121,7 @@ export default function MenuItem({
}); });
}; };
/** @param {KeyboardEvent} event */
const onKeyDown = event => { const onKeyDown = event => {
switch (normalizeKeyName(event.key)) { switch (normalizeKeyName(event.key)) {
case 'ArrowRight': case 'ArrowRight':
......
import { normalizeKeyName } from '@hypothesis/frontend-shared'; import { normalizeKeyName } from '@hypothesis/frontend-shared';
import { useEffect, useRef } from 'preact/hooks'; import { useEffect, useRef } from 'preact/hooks';
/** @param {HTMLElement} element */
function isElementVisible(element) { function isElementVisible(element) {
return element.offsetParent !== null; return element.offsetParent !== null;
} }
...@@ -10,7 +11,7 @@ function isElementVisible(element) { ...@@ -10,7 +11,7 @@ function isElementVisible(element) {
* @prop {string} [className] * @prop {string} [className]
* @prop {(e: KeyboardEvent) => any} [closeMenu] - Callback when the menu is closed via keyboard input * @prop {(e: KeyboardEvent) => any} [closeMenu] - Callback when the menu is closed via keyboard input
* @prop {boolean} [visible] - When true`, sets focus on the first item in the list * @prop {boolean} [visible] - When true`, sets focus on the first item in the list
* @prop {object} children - Array of nodes which may contain <MenuItems> or any nodes * @prop {import('preact').ComponentChildren} children - Array of nodes which may contain <MenuItems> or any nodes
*/ */
/** /**
...@@ -47,6 +48,7 @@ export default function MenuKeyboardNavigation({ ...@@ -47,6 +48,7 @@ export default function MenuKeyboardNavigation({
}; };
}, [visible]); }, [visible]);
/** @param {KeyboardEvent} event */
const onKeyDown = event => { const onKeyDown = event => {
const menuItems = Array.from( const menuItems = Array.from(
/** @type {NodeListOf<HTMLElement>} */ /** @type {NodeListOf<HTMLElement>} */
......
...@@ -56,6 +56,7 @@ function NotebookView({ loadAnnotationsService, streamer }) { ...@@ -56,6 +56,7 @@ function NotebookView({ loadAnnotationsService, streamer }) {
// of them: this is a performance safety valve. // of them: this is a performance safety valve.
const maxResults = 5000; const maxResults = 5000;
/** @param {Error} error */
const onLoadError = error => { const onLoadError = error => {
if (error instanceof ResultSizeError) { if (error instanceof ResultSizeError) {
setHasTooManyAnnotationsError(true); setHasTooManyAnnotationsError(true);
...@@ -101,7 +102,7 @@ function NotebookView({ loadAnnotationsService, streamer }) { ...@@ -101,7 +102,7 @@ function NotebookView({ loadAnnotationsService, streamer }) {
} }
}, [loadAnnotationsService, groupId, store]); }, [loadAnnotationsService, groupId, store]);
// Pagination-page-changing callback /** @param {number} newPage */
const onChangePage = newPage => { const onChangePage = newPage => {
setPaginationPage(newPage); setPaginationPage(newPage);
}; };
......
...@@ -22,13 +22,17 @@ function PaginationNavigation({ currentPage, onChangePage, totalPages }) { ...@@ -22,13 +22,17 @@ function PaginationNavigation({ currentPage, onChangePage, totalPages }) {
const hasPreviousPage = currentPage > 1; const hasPreviousPage = currentPage > 1;
const pageNumbers = pageNumberOptions(currentPage, totalPages); const pageNumbers = pageNumberOptions(currentPage, totalPages);
const changePageTo = (pageNumber, eventTarget) => { /**
* @param {number} pageNumber
* @param {HTMLElement} element
*/
const changePageTo = (pageNumber, element) => {
onChangePage(pageNumber); onChangePage(pageNumber);
// Because changing pagination page doesn't reload the page (as it would // Because changing pagination page doesn't reload the page (as it would
// in a "traditional" HTML context), the clicked-upon navigation button // in a "traditional" HTML context), the clicked-upon navigation button
// will awkwardly retain focus unless it is actively removed. // will awkwardly retain focus unless it is actively removed.
// TODO: Evaluate this for a11y issues // TODO: Evaluate this for a11y issues
/** @type HTMLElement */ (eventTarget)?.blur(); element.blur();
}; };
return ( return (
...@@ -39,7 +43,12 @@ function PaginationNavigation({ currentPage, onChangePage, totalPages }) { ...@@ -39,7 +43,12 @@ function PaginationNavigation({ currentPage, onChangePage, totalPages }) {
classes="PaginationPageButton" classes="PaginationPageButton"
icon="arrow-left" icon="arrow-left"
title="Go to previous page" title="Go to previous page"
onClick={e => changePageTo(currentPage - 1, e.target)} onClick={e =>
changePageTo(
currentPage - 1,
/** @type {HTMLElement} */ (e.target)
)
}
variant="dark" variant="dark"
> >
prev prev
...@@ -57,7 +66,9 @@ function PaginationNavigation({ currentPage, onChangePage, totalPages }) { ...@@ -57,7 +66,9 @@ function PaginationNavigation({ currentPage, onChangePage, totalPages }) {
key={`page-${idx}`} key={`page-${idx}`}
title={`Go to page ${page}`} title={`Go to page ${page}`}
pressed={page === currentPage} pressed={page === currentPage}
onClick={e => changePageTo(page, e.target)} onClick={e =>
changePageTo(page, /** @type {HTMLElement} */ (e.target))
}
variant="dark" variant="dark"
> >
{page.toString()} {page.toString()}
...@@ -73,7 +84,12 @@ function PaginationNavigation({ currentPage, onChangePage, totalPages }) { ...@@ -73,7 +84,12 @@ function PaginationNavigation({ currentPage, onChangePage, totalPages }) {
icon="arrow-right" icon="arrow-right"
iconPosition="right" iconPosition="right"
title="Go to next page" title="Go to next page"
onClick={e => changePageTo(currentPage + 1, e.target)} onClick={e =>
changePageTo(
currentPage + 1,
/** @type {HTMLElement} */ (e.target)
)
}
variant="dark" variant="dark"
> >
next next
......
...@@ -36,6 +36,7 @@ export default function SearchInput({ alwaysExpanded, query, onSearch }) { ...@@ -36,6 +36,7 @@ export default function SearchInput({ alwaysExpanded, query, onSearch }) {
// The query that the user is currently typing, but may not yet have applied. // The query that the user is currently typing, but may not yet have applied.
const [pendingQuery, setPendingQuery] = useState(query); const [pendingQuery, setPendingQuery] = useState(query);
/** @param {Event} e */
const onSubmit = e => { const onSubmit = e => {
e.preventDefault(); e.preventDefault();
if (input.current.value || prevQuery) { if (input.current.value || prevQuery) {
......
...@@ -35,8 +35,10 @@ function ShareLink({ label, iconName, uri }) { ...@@ -35,8 +35,10 @@ function ShareLink({ label, iconName, uri }) {
/** /**
* A list of share links to social-media platforms. * A list of share links to social-media platforms.
*
* @param {ShareLinksProps} props
*/ */
function ShareLinks({ shareURI }) { export default function ShareLinks({ shareURI }) {
// This is the double-encoded format needed for other services (the entire // This is the double-encoded format needed for other services (the entire
// URI needs to be encoded because it's used as the value of querystring params) // URI needs to be encoded because it's used as the value of querystring params)
const encodedURI = encodeURIComponent(shareURI); const encodedURI = encodeURIComponent(shareURI);
...@@ -65,5 +67,3 @@ function ShareLinks({ shareURI }) { ...@@ -65,5 +67,3 @@ function ShareLinks({ shareURI }) {
</ul> </ul>
); );
} }
export default ShareLinks;
...@@ -18,6 +18,7 @@ import SearchInput from './SearchInput'; ...@@ -18,6 +18,7 @@ import SearchInput from './SearchInput';
function StreamSearchInput({ router }) { function StreamSearchInput({ router }) {
const store = useStoreProxy(); const store = useStoreProxy();
const query = store.routeParams().q; const query = store.routeParams().q;
/** @param {string} query */
const setQuery = query => { const setQuery = query => {
// Re-route the user to `/stream` if they are on `/a/:id` and then set // Re-route the user to `/stream` if they are on `/a/:id` and then set
// the search query. // the search query.
......
...@@ -24,10 +24,9 @@ function StreamView({ api, toastMessenger }) { ...@@ -24,10 +24,9 @@ function StreamView({ api, toastMessenger }) {
/** /**
* Fetch annotations from the API and display them in the stream. * Fetch annotations from the API and display them in the stream.
*
* @param {string} query - The user-supplied search query
*/ */
const loadAnnotations = useCallback( const loadAnnotations = useCallback(
/** @param {string} query */
async query => { async query => {
const queryParams = { const queryParams = {
_separate_replies: true, _separate_replies: true,
......
...@@ -76,7 +76,7 @@ function ToastMessage({ message, onDismiss }) { ...@@ -76,7 +76,7 @@ function ToastMessage({ message, onDismiss }) {
/** /**
* @typedef ToastMessagesProps * @typedef ToastMessagesProps
* @prop {object} toastMessenger - Injected service * @prop {import('../services/toast-messenger').ToastMessengerService} toastMessenger
*/ */
/** /**
......
...@@ -30,6 +30,9 @@ function TutorialInstruction({ commandName, iconName }) { ...@@ -30,6 +30,9 @@ function TutorialInstruction({ commandName, iconName }) {
/** /**
* Tutorial for using the sidebar app * Tutorial for using the sidebar app
*
* @param {object} props
* @param {import('../../types/config').SidebarSettings} props.settings
*/ */
function Tutorial({ settings }) { function Tutorial({ settings }) {
const canCreatePrivateGroups = !isThirdPartyService(settings); const canCreatePrivateGroups = !isThirdPartyService(settings);
......
...@@ -48,6 +48,7 @@ function UserMenu({ auth, frameSync, onLogout, settings }) { ...@@ -48,6 +48,7 @@ function UserMenu({ auth, frameSync, onLogout, settings }) {
const isNotebookEnabled = store.isFeatureEnabled('notebook_launch'); const isNotebookEnabled = store.isFeatureEnabled('notebook_launch');
const [isOpen, setOpen] = useState(false); const [isOpen, setOpen] = useState(false);
/** @param {keyof import('../../types/config').Service} feature */
const serviceSupports = feature => service && !!service[feature]; const serviceSupports = feature => service && !!service[feature];
const isSelectableProfile = const isSelectableProfile =
...@@ -61,6 +62,8 @@ function UserMenu({ auth, frameSync, onLogout, settings }) { ...@@ -61,6 +62,8 @@ function UserMenu({ auth, frameSync, onLogout, settings }) {
// Temporary access to the Notebook without feature flag: // Temporary access to the Notebook without feature flag:
// type the key 'n' when user menu is focused/open // type the key 'n' when user menu is focused/open
/** @param {KeyboardEvent} event */
const onKeyDown = event => { const onKeyDown = event => {
if (event.key === 'n') { if (event.key === 'n') {
onSelectNotebook(); onSelectNotebook();
......
...@@ -22,6 +22,7 @@ export function useUserFilterOptions() { ...@@ -22,6 +22,7 @@ export function useUserFilterOptions() {
return useMemo(() => { return useMemo(() => {
// Determine unique users (authors) in annotation collection // Determine unique users (authors) in annotation collection
/** @type {Record<string, string>} */
const users = {}; const users = {};
annotations.forEach(annotation => { annotations.forEach(annotation => {
const username_ = username(annotation.user); const username_ = username(annotation.user);
......
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