Files
outline/app/components/ActionButton.tsx
Apoorv Mishra 6b286d82b8 Ability to choose publish location for a document (#4582)
* feat: initial base structure

* feat: utils for constructing and flattening collection tree

* feat: basic demo to display tree-like structure with virtualization

* feat: make it searchable

* feat: row component

* fix: handle row selection

* fix: scroll jitter

* fix: popover max-height to eliminate extra scroll

* fix: position scrollbar correctly

* fix: do not sort to maintain correct tree-like view

* feat: footer

* fix: scroll to selected item

* fix: deselect item

* fix: display selected location in footer

* fix: deselect item if any upon search trigger

* fix: create draft without collection

* fix: pass down collectionId to all the nodes

* feat: publish document under selected location

* fix: move the doc post publish in case it is supposed to be a nested doc

* fix: wrap text for selected location

* fix: footer background in dark mode and unused css

* fix: popover height in small devices

* fix: no need to spread

* refactor: remove outline

* refactor: border-radius is common

* refactor: remove active and focus

* fix: do not shrink spacer

* fix: scroll list padding with correctly adjusted scrolling

* refactor: use constants

* fix: use padding in favor of spacer

* refactor: border attrs not needed

* refactor: control title padding and icon size centrally

* fix: rename param

* fix: import path

* fix: refactor styles, avoid magic numbers

* fix: type err

* feat: make rows collapsible

* fix: fully expanded without disclosure upon search

* fix: use modal in place of popover

* fix: collapse descendants

* fix: rename PublishPopover to PublishModal

* fix: adjust collapse icon as part of tree view

* fix: enable keyboard navigation

* not sure why collapse and expand shortcuts are not working

* fix: row expansion and search box focus and blur

* fix: remove css hover, handle it via active prop

* fix: discard tree like view for search results

* fix: minor tweaks

* refactor: no need to pass onPublish

* refactor: remove unnecessary attrs from search component

* fix: publish button text

* fix: reset intial scroll offset to 0 on search

* fix: remove search highlights

* fix: clean up search component

* refactor: search and row collapse

* refactor: PublishLocation

* fix: show emoji or star icon if present

* fix: shift focus only from top item

* fix: leading emoji

* fix: baseline text

* fix: make path tertiary

* fix: do not show path for collections

* fix: path text color upon selection

* fix: deleted collection case

* fix: no results found

* fix: space around slash

* Refinement, some small refactors

* fix: Publish shortcut, use Button action

* Allow new document creation from command menu without active collection

* fix: duplicate

* fix: Unneccessary truncation

* fix: Scroll on expand/collapse
Remove wraparound

* fix: tsc

* fix: Horizontal overflow on PublishLocation
Remove pointless moveTo method

* fix: Missing translation

* Remove method indirection
Show expanded collection icon in tree when expanded

* Shrink font size a point

* Remove feature flag

* fix: Path color contrast in light mode
Remove unused expanded/show attributes

* shrink -> collapse, fix expanded disclosure without items after searching

* Mobile styles

* fix: scroll just into view

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2023-01-23 17:38:24 -08:00

81 lines
2.1 KiB
TypeScript

import * as React from "react";
import Tooltip, { Props as TooltipProps } from "~/components/Tooltip";
import { Action, ActionContext } from "~/types";
export type Props = React.ComponentPropsWithoutRef<"button"> & {
/** Show the button in a disabled state */
disabled?: boolean;
/** Hide the button entirely if action is not applicable */
hideOnActionDisabled?: boolean;
/** Action to use on button */
action?: Action;
/** Context of action, must be provided with action */
context?: ActionContext;
/** If tooltip props are provided the button will be wrapped in a tooltip */
tooltip?: Omit<TooltipProps, "children">;
};
/**
* Button that can be used to trigger an action definition.
*/
const ActionButton = React.forwardRef(
(
{ action, context, tooltip, hideOnActionDisabled, ...rest }: Props,
ref: React.Ref<HTMLButtonElement>
) => {
const [executing, setExecuting] = React.useState(false);
const disabled = rest.disabled;
if (!context || !action) {
return <button {...rest} ref={ref} />;
}
const actionContext = { ...context, isButton: true };
if (
action?.visible &&
!action.visible(actionContext) &&
hideOnActionDisabled
) {
return null;
}
const label =
typeof action.name === "function"
? action.name(actionContext)
: action.name;
const button = (
<button
{...rest}
aria-label={label}
disabled={disabled || executing}
ref={ref}
onClick={
action?.perform && actionContext
? (ev) => {
ev.preventDefault();
ev.stopPropagation();
const response = action.perform?.(actionContext);
if (response?.finally) {
setExecuting(true);
response.finally(() => setExecuting(false));
}
}
: rest.onClick
}
>
{rest.children ?? label}
</button>
);
if (tooltip) {
return <Tooltip {...tooltip}>{button}</Tooltip>;
}
return button;
}
);
export default ActionButton;