Unverified Commit e76b5470 authored by Kyle Keating's avatar Kyle Keating Committed by GitHub

Improve typechecking for several components and their dependencies

- TagList
- TagEditor
- MarkdownEditor
- Excerpt
- AutocompleteList
- AnnotationBody
parent 6c76613c
......@@ -11,8 +11,24 @@ import MarkdownView from './markdown-view';
import TagEditor from './tag-editor';
import TagList from './tag-list';
/** @typedef {import("../../types/api").Annotation} Annotation */
/**
* @typedef AnnotationBodyProps
* @prop {Annotation} annotation - The annotation in question
* @prop {boolean} [isEditing] - Whether to display the body in edit mode (if true) or view mode.
* @prop {(a: Object<'tags', string[]>) => void} [onEditTags] - Callback invoked when the user edits tags.
* @prop {(a?: Object<'text', string>) => void} [onEditText] - Callback invoked when the user edits the content of the annotation body.
* @prop {string[]} tags
* @prop {string} text -
* The markdown annotation body, which is either rendered as HTML (if `isEditing`
* is false) or displayed in a text area otherwise.
*/
/**
* Display the rendered content of an annotation.
*
* @param {AnnotationBodyProps} props
*/
export default function AnnotationBody({
annotation,
......@@ -63,11 +79,14 @@ export default function AnnotationBody({
)}
{isCollapsible && !isEditing && (
<div className="annotation-body__collapse-toggle">
{/* @ts-ignore - TODO: Button props need to be fixed */}
<Button
buttonText={toggleText}
className="annotation-body__collapse-toggle-button"
isExpanded={!isCollapsed}
onClick={() => setIsCollapsed(!isCollapsed)}
onClick={() => {
setIsCollapsed(!isCollapsed);
}}
aria-label="Toggle visibility of full annotation text"
title="Toggle visibility of full annotation text"
/>
......@@ -80,31 +99,10 @@ export default function AnnotationBody({
}
AnnotationBody.propTypes = {
/**
* The annotation in question
*/
annotation: propTypes.object.isRequired,
/**
* Whether to display the body in edit mode (if true) or view mode.
*/
isEditing: propTypes.bool,
/**
* Callback invoked when the user edits tags.
*/
onEditTags: propTypes.func,
/**
* Callback invoked when the user edits the content of the annotation body.
*/
onEditText: propTypes.func,
tags: propTypes.array.isRequired,
/**
* The markdown annotation body, which is either rendered as HTML (if `isEditing`
* is false) or displayed in a text area otherwise.
*/
text: propTypes.string,
};
......@@ -5,6 +5,25 @@ import propTypes from 'prop-types';
const defaultListFormatter = item => item;
/**
* @template T
* @typedef AutocompleteListProps
* @prop {number} [activeItem] - The index of the highlighted item.
* @prop {string} [id] - Optional unique HTML attribute id. This can be used
* for parent `aria-controls` coupling.
* @prop {string} [itemPrefixId] - Optional unique HTML attribute id prefix
* for each item in the list. The final value of each items' id is
* `{itemPrefixId}{activeItem}`
* @prop {T[]} list - The list of items to render. This can be a simple
* list of strings or a list of objects when used with listFormatter.
* @prop {(item: T, index?: number) => any} [listFormatter] - An optional formatter
* to render each item inside an <li> tag This is useful if the list is an array of
* objects rather than just strings.
* @prop {(item: T) => void} onSelectItem - Callback when an item is clicked with
* the mouse.
* @prop {boolean} [open] - Is the list open or closed?
*/
/**
* Custom autocomplete component. Use this in conjunction with an <input> field.
* To make this component W3 accessibility compliant, it is is intended to be
......@@ -12,8 +31,10 @@ const defaultListFormatter = item => item;
* used by itself.
*
* Modeled after the "ARIA 1.1 Combobox with Listbox Popup"
*
* @template T
* @param {AutocompleteListProps<T>} props
*/
export default function AutocompleteList({
activeItem = -1,
id,
......@@ -65,7 +86,7 @@ export default function AutocompleteList({
>
<ul
className="autocomplete-list__items"
tabIndex="-1"
tabIndex={-1}
aria-label="Suggestions"
role="listbox"
{...props}
......@@ -77,39 +98,11 @@ export default function AutocompleteList({
}
AutocompleteList.propTypes = {
/**
* The index of the highlighted item.
*/
activeItem: propTypes.number,
/**
* Optional unique HTML attribute id. This can be used for
* parent `aria-controls` coupling.
*/
id: propTypes.string,
/**
* Optional unique HTML attribute id prefix for each item in the list.
* The final value of each items' id is `{itemPrefixId}{activeItem}`
*/
itemPrefixId: propTypes.string,
/**
* The list of items to render. This can be a simple list of
* strings or a list of objects when used with listFormatter.
*/
list: propTypes.array.isRequired,
/**
* An optional formatter to render each item inside an <li> tag
* This is useful if the list is an array of objects rather than
* just strings.
*/
listFormatter: propTypes.func,
/**
* Callback when an item is clicked with the mouse.
* (item, index) => {}
*/
onSelectItem: propTypes.func.isRequired,
/**
* Is the list open or closed?
*/
open: propTypes.bool,
};
......@@ -17,7 +17,7 @@ export default function Button({
icon = '',
isExpanded,
isPressed,
onClick = () => null,
onClick = () => {},
style = {},
title,
}) {
......
......@@ -7,9 +7,18 @@ import observeElementSize from '../util/observe-element-size';
import { withServices } from '../util/service-context';
import { applyTheme } from '../util/theme';
/**
* @typedef InlineControlsProps
* @prop {boolean} [isCollapsed]
* @prop {(collapsed: boolean) => any} [setCollapsed]
* @prop {Object} [linkStyle]
*/
/**
* An optional toggle link at the bottom of an excerpt which controls whether
* it is expanded or collapsed.
*
* @param {InlineControlsProps} props
*/
function InlineControls({ isCollapsed, setCollapsed, linkStyle = {} }) {
const toggleLabel = isCollapsed ? 'More' : 'Less';
......@@ -39,12 +48,36 @@ InlineControls.propTypes = {
const noop = () => {};
/**
* @typedef ExcerptProps
* @prop {Object} [children]
* @prop {boolean} [inlineControls] - If `true`, the excerpt provides internal
* controls to expand and collapse the content. If `false`, the caller sets
* the collapsed state via the `collapse` prop. When using inline controls,
* the excerpt is initially collapsed.
* @prop {boolean} [collapse] - If the content should be truncated if its height
* exceeds `collapsedHeight + overflowThreshold`. This prop is only used if
* `inlineControls` is false.
* @prop {number} collapsedHeight - Maximum height of the container, in pixels,
* when it is collapsed.
* @prop {number} [overflowThreshold] - An additional margin of pixels by which
* the content height can exceed `collapsedHeight` before it becomes collapsible.
* @prop {(isCollapsible?: boolean) => any} [onCollapsibleChanged] - Called when the content height
* exceeds or falls below `collapsedHeight + overflowThreshold`.
* @prop {(collapsed?: boolean) => any} [onToggleCollapsed] - When `inlineControls` is `false`, this
* function is called when the user requests to expand the content by clicking a
* zone at the bottom of the container.
* @prop {Object} [settings] - Used for theming.
*/
/**
* A container which truncates its content when they exceed a specified height.
*
* The collapsed state of the container can be handled either via internal
* controls (if `inlineControls` is `true`) or by the caller using the
* `collapse` prop.
*
* @param {ExcerptProps} props
*/
function Excerpt({
children,
......@@ -61,7 +94,7 @@ function Excerpt({
);
// Container for the excerpt's content.
const contentElement = useRef(null);
const contentElement = useRef(/** @type {HTMLDivElement|null} */ (null));
// Measured height of `contentElement` in pixels.
const [contentHeight, setContentHeight] = useState(0);
......@@ -94,6 +127,7 @@ function Excerpt({
const isCollapsed = inlineControls ? collapsedByInlineControls : collapse;
const isExpandable = isOverflowing && isCollapsed;
/** @type {Object} */
const contentStyle = {};
if (contentHeight !== 0) {
contentStyle['max-height'] = isExpandable ? collapsedHeight : contentHeight;
......@@ -132,48 +166,12 @@ function Excerpt({
Excerpt.propTypes = {
children: propTypes.object,
/**
* If `true`, the excerpt provides internal controls to expand and collapse
* the content. If `false`, the caller sets the collapsed state via the
* `collapse` prop.
*
* When using inline controls, the excerpt is initially collapsed.
*/
inlineControls: propTypes.bool,
/**
* If the content should be truncated if its height exceeds
* `collapsedHeight + overflowThreshold`.
*
* This prop is only used if `inlineControls` is false.
*/
collapse: propTypes.bool,
/**
* Maximum height of the container, in pixels, when it is collapsed.
*/
collapsedHeight: propTypes.number,
/**
* An additional margin of pixels by which the content height can exceed
* `collapsedHeight` before it becomes collapsible.
*/
overflowThreshold: propTypes.number,
/**
* Called when the content height exceeds or falls below `collapsedHeight + overflowThreshold`.
*/
onCollapsibleChanged: propTypes.func,
/**
* When `inlineControls` is `false`, this function is called when the user
* requests to expand the content by clicking a zone at the bottom of the
* container.
*/
onToggleCollapsed: propTypes.func,
// Used for theming.
settings: propTypes.object,
};
......
......@@ -4,17 +4,17 @@ import { normalizeKeyName } from '../../../shared/browser-compatibility-utils';
import { listen } from '../../util/dom';
/**
* @typedef Ref
* @prop current {Node} - HTML node
*
* A ref object attached to a HTML node.
* @template T
* @typedef {import("preact/hooks").Ref<T>} Ref
*/
/**
* @typedef PreactRef
* @prop current {Object} - preact component object
*
* A ref object attached to a custom preact component.
* @typedef PreactElement
* @prop {Node} base
*/
/**
* @typedef {Ref<HTMLButtonElement> & Ref<PreactElement>} PreactRef
*/
/**
......@@ -28,11 +28,11 @@ import { listen } from '../../util/dom';
* Limitation: This will not work when attached to a custom component that has
* more than one element nested under a root <Fragment>
*
* @param {Ref|PreactRef} closeableEl - ref object:
* @param {PreactRef} closeableEl - ref object:
* Reference to a DOM element or preat component
* that should be closed when DOM elements external
* to it are interacted with or `Esc` is pressed
* @param {bool} isOpen - Whether the element is currently open. This hook does
* @param {boolean} isOpen - Whether the element is currently open. This hook does
* not attach event listeners/do anything if it's not.
* @param {() => void} handleClose - A function that will do the actual closing
* of `closeableEl`
......@@ -46,7 +46,7 @@ export default function useElementShouldClose(
* Helper to return the underlying node object whether
* `closeableEl` is attached to an HTMLNode or Preact component.
*
* @param {Preact ref} closeableEl
* @param {PreactRef} closeableEl
* @returns {Node}
*/
......@@ -67,7 +67,9 @@ export default function useElementShouldClose(
}
// Close element when user presses Escape key, regardless of focus.
const removeKeyDownListener = listen(document.body, ['keydown'], event => {
const removeKeyDownListener = listen(document.body, ['keydown'], (
/** @type {KeyboardEvent}*/ event
) => {
if (normalizeKeyName(event.key) === 'Escape') {
handleClose();
}
......@@ -80,7 +82,7 @@ export default function useElementShouldClose(
'focus',
event => {
const current = getCurrentNode(closeableEl);
if (!current.contains(event.target)) {
if (!current.contains(/** @type {Node} */ (event.target))) {
handleClose();
}
},
......@@ -94,7 +96,7 @@ export default function useElementShouldClose(
['mousedown', 'click'],
event => {
const current = getCurrentNode(closeableEl);
if (!current.contains(event.target)) {
if (!current.contains(/** @type {Node} */ (event.target))) {
handleClose();
}
},
......
......@@ -31,7 +31,7 @@ const SHORTCUT_KEYS = {
* Apply a toolbar command to an editor input field.
*
* @param {string} command
* @param {HTMLInputElement} inputEl
* @param {HTMLInputElement|HTMLTextAreaElement} inputEl
*/
function handleToolbarCommand(command, inputEl) {
const update = newStateFn => {
......@@ -94,11 +94,24 @@ function handleToolbarCommand(command, inputEl) {
}
}
/**
* @typedef ToolbarButtonProps
* @prop {Object} buttonRef
* @prop {boolean} [disabled]
* @prop {string} [iconName]
* @prop {string} [label]
* @prop {(e: MouseEvent) => void} onClick
* @prop {string} [shortcutKey]
* @prop {number} tabIndex
* @prop {string} [title]
*/
/** @param {ToolbarButtonProps} props */
function ToolbarButton({
buttonRef,
disabled = false,
iconName,
label = null,
label,
onClick,
shortcutKey,
tabIndex,
......@@ -147,9 +160,14 @@ ToolbarButton.propTypes = {
};
/**
* @typedef {string} ButtonID
* A unique string that can be one of one of:
* [bold, italic, quote, link, image, math, numlist, list, preview, help]
* @typedef {'bold'|'italic'|'quote'|'link'|'image'|'math'|'numlist'|'list'|'preview'|'help'} ButtonID
*/
/**
* @typedef ToolbarProps
* @prop {boolean} [isPreviewing] - `true` if the editor's "Preview" mode is active.
* @prop {(a: ButtonID) => any} [onCommand] - Callback invoked with the selected command when a toolbar button is clicked.
* @prop {() => any} [onTogglePreview] - Callback invoked when the "Preview" toggle button is clicked.
*/
/**
......@@ -159,6 +177,8 @@ ToolbarButton.propTypes = {
*
* Canonical example
* https://www.w3.org/TR/wai-aria-practices/examples/toolbar/toolbar.html
*
* @param {ToolbarProps} props
*/
function Toolbar({ isPreviewing, onCommand, onTogglePreview }) {
const buttonIds = {
......@@ -247,8 +267,8 @@ function Toolbar({ isPreviewing, onCommand, onTogglePreview }) {
* Each element should be set to -1 unless its the
* active roving index, in which case it will be 0.
*
* @param {ButtonID} id
* @return {number} index - An index from `buttonIds`
* @param {number} index - An index from `buttonIds`
* @return {number}
*/
const getTabIndex = index => {
if (rovingElement === index) {
......@@ -364,18 +384,25 @@ function Toolbar({ isPreviewing, onCommand, onTogglePreview }) {
}
Toolbar.propTypes = {
/** `true` if the editor's "Preview" mode is active. */
isPreviewing: propTypes.bool,
/** Callback invoked with the selected command when a toolbar button is clicked. */
onCommand: propTypes.func,
/** Callback invoked when the "Preview" toggle button is clicked. */
onTogglePreview: propTypes.func,
};
/**
* @typedef MarkdownEditorProps
* @prop {string} label - An accessible label for the input field.
* @prop {string} [text] - The markdown text to edit.
* @prop {(a?: Object<'text', string>) => void} [onEditText]
* - Callback invoked with `{ text }` object when user edits text.
* TODO: Simplify this callback to take just a string rather than an object once the
* parent component is converted to Preact.
*/
/**
* Viewer/editor for the body of an annotation in markdown format.
*
* @param {MarkdownEditorProps} props
*/
export default function MarkdownEditor({
label = '',
......@@ -386,7 +413,7 @@ export default function MarkdownEditor({
const [preview, setPreview] = useState(false);
// The input element where the user inputs their comment.
const input = useRef(null);
const input = useRef(/** @type {HTMLTextAreaElement|null} */ (null));
useEffect(() => {
if (!preview) {
......@@ -435,7 +462,11 @@ export default function MarkdownEditor({
ref={input}
onClick={e => e.stopPropagation()}
onKeyDown={handleKeyDown}
onInput={e => onEditText({ text: e.target.value })}
onInput={e => {
onEditText({
text: /** @type {HTMLTextAreaElement} */ (e.target).value,
});
}}
value={text}
/>
)}
......@@ -444,19 +475,7 @@ export default function MarkdownEditor({
}
MarkdownEditor.propTypes = {
/**
* An accessible label for the input field.
*/
label: propTypes.string.isRequired,
/** The markdown text to edit. */
text: propTypes.string,
/**
* Callback invoked with `{ text }` object when user edits text.
*
* TODO: Simplify this callback to take just a string rather than an object
* once the parent component is converted to Preact.
*/
onEditText: propTypes.func,
};
......@@ -13,16 +13,24 @@ import useElementShouldClose from './hooks/use-element-should-close';
// Global counter used to create a unique id for each instance of a TagEditor
let tagEditorIdCounter = 0;
/**
* @typedef TagEditorProps
* @prop {(a: Object<'tags', string[]>) => any} onEditTags - Callback that saves the tag list.
* @prop {string[]} tagList - The list of editable tags as strings.
* @prop {Object} tags - Services
*/
/**
* Component to edit annotation's tags.
*
* Component accessibility is modeled after "Combobox with Listbox Popup Examples" found here:
* https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
*
* @param {TagEditorProps} props
*/
function TagEditor({ onEditTags, tags: tagsService, tagList }) {
const inputEl = useRef(null);
const [suggestions, setSuggestions] = useState([]);
const inputEl = useRef(/** @type {HTMLInputElement|null} */ (null));
const [suggestions, setSuggestions] = useState(/** @type {string[]} */ ([]));
const [activeItem, setActiveItem] = useState(-1); // -1 is unselected
const [suggestionsListOpen, setSuggestionsListOpen] = useState(false);
const [tagEditorId] = useState(() => {
......@@ -31,7 +39,8 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
});
// Set up callback to monitor outside click events to close the AutocompleteList
const closeWrapperRef = useRef();
const closeWrapperRef = useRef(/** @type {HTMLElement|null} */ (null));
/** @ts-ignore - TODO: fix useElementShouldClose Ref types */
useElementShouldClose(closeWrapperRef, suggestionsListOpen, () => {
setSuggestionsListOpen(false);
});
......@@ -42,9 +51,9 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
* Helper function that returns a list of suggestions less any
* results also found from the duplicates list.
*
* @param {Array<string>} suggestions - Original list of suggestions
* @param {Array<string>} duplicates - Items to be removed from the result
* @return {Array<string>}
* @param {string[]} suggestions - Original list of suggestions
* @param {string[]} duplicates - Items to be removed from the result
* @return {string[]}
*/
const removeDuplicates = (suggestions, duplicates) => {
const suggestionsSet = [];
......@@ -73,11 +82,14 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
setSuggestions(removeDuplicates(suggestions, tagList));
setSuggestionsListOpen(suggestions.length > 0);
}
setActiveItem(-1);
};
/**
* Handle changes to this annotation's tags
*
* @param {string[]} tagList
*/
const updateTags = tagList => {
// update suggested tags list via service
......@@ -100,6 +112,8 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
/**
* Adds a tag to the annotation equal to the value of the input field
* and then clears out the suggestions list and the input field.
*
* @param {string} newTag
*/
const addTag = newTag => {
const value = newTag.trim();
......@@ -115,12 +129,15 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
setSuggestionsListOpen(false);
setActiveItem(-1);
inputEl.current.value = '';
inputEl.current.focus();
const input = inputEl.current;
input.value = '';
input.focus();
};
/**
* Update the suggestions if the user changes the value of the input
*
* @param {import("preact").JSX.TargetedEvent<HTMLInputElement, InputEvent>} e
*/
const handleOnInput = e => {
if (
......@@ -135,6 +152,8 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
/**
* Callback when the user clicked one of the items in the suggestions list.
* This will add a new tag.
*
* @param {string} item
*/
const handleSelect = item => {
if (item) {
......@@ -176,6 +195,8 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
* Keydown handler for keyboard navigation of the suggestions list
* and when the user presses "Enter" or ","" to add a new typed item not
* found in the suggestions list
*
* @param {KeyboardEvent} e
*/
const handleKeyDown = e => {
switch (normalizeKeyName(e.key)) {
......@@ -191,7 +212,7 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
case ',':
if (activeItem === -1) {
// nothing selected, just add the typed text
addTag(inputEl.current.value);
addTag(/** @type {HTMLInputElement} */ (inputEl.current).value);
} else {
addTag(suggestions[activeItem]);
}
......@@ -288,27 +309,12 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
);
}
/**
* @typedef Tag
* @param tag {string} - The tag text
*/
TagEditor.propTypes = {
/**
* Callback that saves the tag list.
*
* @param {Array<Tag>} - Array of tags to save
*/
onEditTags: propTypes.func.isRequired,
/* The list of editable tags as strings. */
tagList: propTypes.array.isRequired,
/** Services */
tags: propTypes.object.isRequired,
serviceUrl: propTypes.func.isRequired,
};
TagEditor.injectedProps = ['serviceUrl', 'tags'];
TagEditor.injectedProps = ['tags'];
export default withServices(TagEditor);
......@@ -5,8 +5,19 @@ import propTypes from 'prop-types';
import { isThirdPartyUser } from '../util/account-id';
import { withServices } from '../util/service-context';
/** @typedef {import('../../types/api').Annotation} Annotation */
/**
* @typedef TagListProps
* @prop {Annotation} annotation - Annotation that owns the tags.
* @prop {string[]} tags - List of tags as strings.
* @prop {(a: string, b: Object<'tag', string>) => any} [serviceUrl] - Services
* @prop {Object} [settings]
*/
/**
* Component to render an annotation's tags.
* @param {TagListProps} props
*/
function TagList({ annotation, serviceUrl, settings, tags }) {
const renderLink = useMemo(
......@@ -52,19 +63,9 @@ function TagList({ annotation, serviceUrl, settings, tags }) {
);
}
/**
* @typedef Tag
* @param tag {string} - The tag text
*/
TagList.propTypes = {
/* Annotation that owns the tags. */
annotation: propTypes.object.isRequired,
/* List of tags as strings. */
tags: propTypes.array.isRequired,
/** Services */
serviceUrl: propTypes.func,
settings: propTypes.object,
};
......
......@@ -83,14 +83,10 @@ function replaceText(state, pos, length, text) {
* Convert the selected text into a Markdown link.
*
* @param {EditorState} state - The current state of the input field.
* @param {LinkType} linkType - The type of link to insert.
* @param {LinkType} [linkType] - The type of link to insert.
* @return {EditorState} - The new state of the input field.
*/
export function convertSelectionToLink(state, linkType) {
if (typeof linkType === 'undefined') {
linkType = LinkType.ANCHOR_LINK;
}
export function convertSelectionToLink(state, linkType = LinkType.ANCHOR_LINK) {
const selection = state.text.slice(state.selectionStart, state.selectionEnd);
let linkPrefix = '';
......
......@@ -28,7 +28,7 @@ export function getElementHeightWithMargins(element) {
* function that removes the listeners.
*
* @param {HTMLElement} element
* @param {string[]} events
* @param {string[]|string} events
* @param {EventListener} listener
* @param {Object} options
* @param {boolean} [options.useCapture]
......@@ -42,7 +42,7 @@ export function listen(element, events, listener, { useCapture = false } = {}) {
element.addEventListener(event, listener, useCapture)
);
return () => {
events.forEach(event =>
/** @type {string[]} */ (events).forEach(event =>
element.removeEventListener(event, listener, useCapture)
);
};
......
......@@ -19,6 +19,7 @@
"shared/components/*.js",
"sidebar/*.js",
"sidebar/components/*.js",
"sidebar/components/hooks/*.js",
"sidebar/store/modules/*.js",
"sidebar/services/*.js",
"sidebar/util/*.js",
......@@ -31,7 +32,6 @@
// Files in `src/sidebar/components` that may still have errors.
// Remove them from this list as they are resolved.
"sidebar/components/annotation-action-bar.js",
"sidebar/components/annotation-body.js",
"sidebar/components/annotation-header.js",
"sidebar/components/annotation-publish-control.js",
"sidebar/components/annotation-quote.js",
......@@ -39,8 +39,6 @@
"sidebar/components/annotation-share-info.js",
"sidebar/components/annotation-viewer-content.js",
"sidebar/components/annotation.js",
"sidebar/components/autocomplete-list.js",
"sidebar/components/excerpt.js",
"sidebar/components/focused-mode-header.js",
"sidebar/components/group-list-item.js",
"sidebar/components/group-list-section.js",
......@@ -49,7 +47,6 @@
"sidebar/components/hypothesis-app.js",
"sidebar/components/logged-out-message.js",
"sidebar/components/login-prompt-panel.js",
"sidebar/components/markdown-editor.js",
"sidebar/components/menu-item.js",
"sidebar/components/menu.js",
"sidebar/components/moderation-banner.js",
......@@ -65,8 +62,6 @@
"sidebar/components/sort-menu.js",
"sidebar/components/stream-content.js",
"sidebar/components/stream-search-input.js",
"sidebar/components/tag-editor.js",
"sidebar/components/tag-list.js",
"sidebar/components/thread-card.js",
"sidebar/components/thread-list.js",
"sidebar/components/thread.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