mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 06:18:07 +03:00
Clean up Component Utils, use stylex
Summary: I noticed we had both <Row> and <FlexRow>, ostensibly doing the same thing...? Here I combine these, and rewrite the API to allow passing xstyle with stylex styles. This makes it easier to use these components when using stylex. Reviewed By: quark-zju Differential Revision: D54391157 fbshipit-source-id: e4f88aaac2d8564967b27b904f23b0b9b308ee00
This commit is contained in:
parent
05c8e3fa70
commit
1e49f1336e
@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {FlexRow} from './ComponentUtils';
|
||||
import {Row} from './ComponentUtils';
|
||||
import {Tooltip} from './Tooltip';
|
||||
import {t, T} from './i18n';
|
||||
import {configBackedAtom} from './jotaiUtils';
|
||||
@ -41,11 +41,11 @@ export function ChangedFileDisplayTypePicker() {
|
||||
|
||||
const actions = entries.map(([type, options]) => ({
|
||||
label: (
|
||||
<FlexRow>
|
||||
<Row>
|
||||
<Icon icon={displayType === type ? 'check' : 'blank'} slot="start" />
|
||||
<Icon icon={options.icon} slot="start" />
|
||||
{options.label}
|
||||
</FlexRow>
|
||||
</Row>
|
||||
),
|
||||
onClick: () => setDisplayType(type),
|
||||
}));
|
||||
|
@ -11,7 +11,7 @@ import type {ContextMenuItem} from 'shared/ContextMenu';
|
||||
|
||||
import {commitMode, hasUnsavedEditedCommitMessage} from './CommitInfoView/CommitInfoState';
|
||||
import {currentComparisonMode} from './ComparisonView/atoms';
|
||||
import {FlexRow} from './ComponentUtils';
|
||||
import {Row} from './ComponentUtils';
|
||||
import {EducationInfoTip} from './Education';
|
||||
import {HighlightCommitsWhileHovering} from './HighlightedCommits';
|
||||
import {InlineBadge} from './InlineBadge';
|
||||
@ -731,14 +731,14 @@ export function SuccessorInfoToDisplay({successorInfo}: {successorInfo: Successo
|
||||
}[successorType] ?? <T>Rewritten as a newer commit</T>;
|
||||
const isSuccessorPublic = successorType === 'land' || successorType === 'pushrebase';
|
||||
return (
|
||||
<FlexRow style={{gap: 'var(--halfpad)'}}>
|
||||
<Row style={{gap: 'var(--halfpad)'}}>
|
||||
<HighlightCommitsWhileHovering toHighlight={[successorInfo.hash]}>
|
||||
{inner}
|
||||
</HighlightCommitsWhileHovering>
|
||||
<EducationInfoTip>
|
||||
<ObsoleteTip isSuccessorPublic={isSuccessorPublic} />
|
||||
</EducationInfoTip>
|
||||
</FlexRow>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -5,26 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.center-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--pad);
|
||||
}
|
||||
|
||||
/* Workaround missing `scrollbar-width: none` support in Chrome */
|
||||
.hide-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
@ -5,10 +5,31 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {spacing} from './tokens.stylex';
|
||||
import * as stylex from '@stylexjs/stylex';
|
||||
import {Icon} from 'shared/Icon';
|
||||
import {notEmpty} from 'shared/utils';
|
||||
|
||||
import './ComponentUtils.css';
|
||||
|
||||
const styles = stylex.create({
|
||||
center: {
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
flex: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: spacing.pad,
|
||||
},
|
||||
spacer: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
});
|
||||
|
||||
export function LargeSpinner() {
|
||||
return (
|
||||
<div data-testid="loading-spinner">
|
||||
@ -18,26 +39,18 @@ export function LargeSpinner() {
|
||||
}
|
||||
|
||||
export function Center(props: ContainerProps) {
|
||||
const className = addClassName('center-container', props);
|
||||
return (
|
||||
<div {...props} className={className}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function FlexRow(props: FlexProps) {
|
||||
return FlexBox({...props, className: addClassName('flex-row', props)});
|
||||
const {className, ...rest} = props;
|
||||
return <div {...stylexPropsWithClassName(styles.center, className)} {...rest} />;
|
||||
}
|
||||
|
||||
/** Flexbox container with horizontal children. */
|
||||
export function Row(props: FlexProps) {
|
||||
return FlexBox({...props, direction: 'row'});
|
||||
export function Row(props: ContainerProps) {
|
||||
return FlexBox(props, 'row');
|
||||
}
|
||||
|
||||
/** Flexbox container with vertical children. */
|
||||
export function Column(props: FlexProps) {
|
||||
return FlexBox({...props, direction: 'column'});
|
||||
export function Column(props: ContainerProps) {
|
||||
return FlexBox(props, 'column');
|
||||
}
|
||||
|
||||
/** Container that scrolls horizontally. */
|
||||
@ -52,27 +65,24 @@ export function ScrollY(props: ScrollProps) {
|
||||
|
||||
/** Visually empty flex item with `flex-grow: 1` to insert as much space as possible between siblings. */
|
||||
export function FlexSpacer() {
|
||||
return <div className={'spacer'} />;
|
||||
return <div {...stylex.props(styles.spacer)} />;
|
||||
}
|
||||
|
||||
type ContainerProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||
|
||||
type FlexProps = ContainerProps & {
|
||||
direction?: 'row' | 'column';
|
||||
};
|
||||
type ContainerProps = React.DetailedHTMLProps<
|
||||
React.HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
> & {xstyle?: stylex.StyleXStyles};
|
||||
|
||||
/** See `<Row>` and `<Column>`. */
|
||||
function FlexBox(props: FlexProps) {
|
||||
const direction = props.direction ?? 'row';
|
||||
const style: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
flexDirection: direction,
|
||||
flexWrap: 'nowrap',
|
||||
};
|
||||
const mergedProps = {...props, style: {...style, ...props.style}};
|
||||
delete mergedProps.children;
|
||||
delete mergedProps.direction;
|
||||
return <div {...mergedProps}>{props.children}</div>;
|
||||
function FlexBox(props: ContainerProps, flexDirection: 'row' | 'column') {
|
||||
const {className, style, ...rest} = props;
|
||||
return (
|
||||
<div
|
||||
{...stylexPropsWithClassName([styles.flex, props.xstyle].filter(notEmpty), className)}
|
||||
{...rest}
|
||||
style={{flexDirection, ...style}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
type ScrollProps = ContainerProps & {
|
||||
@ -130,6 +140,15 @@ function Scroll(props: ScrollProps) {
|
||||
);
|
||||
}
|
||||
|
||||
function addClassName(name: string, props: FlexProps) {
|
||||
return props.className == null ? name : `${props.className} ${name}`;
|
||||
/**
|
||||
* Like stylex.props(), but also adds in extra classNames.
|
||||
* Useful since `{...stylex.props()}` sets className,
|
||||
* and either overwrites or is overwritten by other `className="..."` props.
|
||||
*/
|
||||
export function stylexPropsWithClassName(
|
||||
style: stylex.StyleXStyles,
|
||||
...names: Array<string | undefined>
|
||||
) {
|
||||
const {className, ...rest} = stylex.props(style);
|
||||
return {...rest, className: className + ' ' + names.filter(notEmpty).join(' ')};
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import type {ThemeColor} from './theme';
|
||||
import type {PreferredSubmitCommand} from './types';
|
||||
import type {ReactNode} from 'react';
|
||||
|
||||
import {FlexRow} from './ComponentUtils';
|
||||
import {Row} from './ComponentUtils';
|
||||
import {confirmShouldSubmitEnabledAtom} from './ConfirmSubmitStack';
|
||||
import {DropdownField, DropdownFields} from './DropdownFields';
|
||||
import {useShowKeyboardShortcutsHelp} from './ISLShortcuts';
|
||||
@ -264,13 +264,13 @@ function OpenFilesCmdSetting() {
|
||||
<pre>sl config --user isl.open-file-cmd '["cmd", "with", "args"]'</pre>
|
||||
</div>
|
||||
)}>
|
||||
<FlexRow>
|
||||
<Row>
|
||||
<T replace={{$cmd: cmdEl}}>Open files in $cmd</T>
|
||||
<Subtle>
|
||||
<T>How to configure?</T>
|
||||
</Subtle>
|
||||
<Icon icon="question" />
|
||||
</FlexRow>
|
||||
</Row>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import type {DagCommitInfo} from './dag/dag';
|
||||
import type {Hash} from './types';
|
||||
|
||||
import {CleanupButton, isStackEligibleForCleanup} from './Cleanup';
|
||||
import {FlexRow} from './ComponentUtils';
|
||||
import {Row} from './ComponentUtils';
|
||||
import {shouldShowSubmitStackConfirmation, useShowConfirmSubmitStack} from './ConfirmSubmitStack';
|
||||
import {HighlightCommitsWhileHovering} from './HighlightedCommits';
|
||||
import {OperationDisabledButton} from './OperationDisabledButton';
|
||||
@ -154,10 +154,10 @@ export function StackActions({hash}: {hash: Hash}): React.ReactElement | null {
|
||||
moreActions.push({
|
||||
label: (
|
||||
<HighlightCommitsWhileHovering key="submit-entire-stack" toHighlight={submittableStack}>
|
||||
<FlexRow>
|
||||
<Row>
|
||||
<Icon icon="cloud-upload" slot="start" />
|
||||
<T>Submit entire stack</T>
|
||||
</FlexRow>
|
||||
</Row>
|
||||
</HighlightCommitsWhileHovering>
|
||||
),
|
||||
onClick: async () => {
|
||||
|
@ -11,7 +11,7 @@ import type {ParsedDiff} from 'shared/patch/parse';
|
||||
import {AvatarImg} from '../Avatar';
|
||||
import serverAPI from '../ClientToServerAPI';
|
||||
import {SplitDiffTable} from '../ComparisonView/SplitDiffView/SplitDiffHunk';
|
||||
import {Column, FlexRow} from '../ComponentUtils';
|
||||
import {Column, Row} from '../ComponentUtils';
|
||||
import {ErrorNotice} from '../ErrorNotice';
|
||||
import {Link} from '../Link';
|
||||
import {Subtle} from '../Subtle';
|
||||
@ -65,6 +65,7 @@ const styles = stylex.create({
|
||||
commentInfo: {
|
||||
gap: spacing.half,
|
||||
marginBlock: spacing.half,
|
||||
alignItems: 'flex-start',
|
||||
},
|
||||
inlineCommentFilename: {
|
||||
marginBottom: spacing.half,
|
||||
@ -96,7 +97,7 @@ const styles = stylex.create({
|
||||
|
||||
function Comment({comment, isTopLevel}: {comment: DiffComment; isTopLevel?: boolean}) {
|
||||
return (
|
||||
<FlexRow {...stylex.props(styles.comment)}>
|
||||
<Row xstyle={styles.comment}>
|
||||
<Column {...stylex.props(styles.left)}>
|
||||
<AvatarImg
|
||||
username={comment.author}
|
||||
@ -104,7 +105,7 @@ function Comment({comment, isTopLevel}: {comment: DiffComment; isTopLevel?: bool
|
||||
{...stylex.props(styles.avatar)}
|
||||
/>
|
||||
</Column>
|
||||
<Column {...stylex.props(styles.commentInfo)}>
|
||||
<Column xstyle={styles.commentInfo}>
|
||||
<b {...stylex.props(styles.author)}>{comment.author}</b>
|
||||
<div>
|
||||
{isTopLevel && comment.filename && (
|
||||
@ -130,7 +131,7 @@ function Comment({comment, isTopLevel}: {comment: DiffComment; isTopLevel?: bool
|
||||
<Comment key={i} comment={reply} />
|
||||
))}
|
||||
</Column>
|
||||
</FlexRow>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
@ -184,10 +185,10 @@ function Reactions({reactions}: {reactions: Array<DiffCommentReaction>}) {
|
||||
const names = reactions.map(r => r.name);
|
||||
return (
|
||||
<Tooltip title={names.join(', ')}>
|
||||
<FlexRow style={{gap: spacing.half}}>
|
||||
<Row style={{gap: spacing.half}}>
|
||||
<span style={{letterSpacing: '-2px'}}>{icons}</span>
|
||||
<span>{total}</span>
|
||||
</FlexRow>
|
||||
</Row>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import type {ExclusiveOr} from 'shared/typeUtils';
|
||||
|
||||
import {holdingAltAtom} from '../ChangedFile';
|
||||
import {debugLogMessageTraffic} from '../ClientToServerAPI';
|
||||
import {FlexRow} from '../ComponentUtils';
|
||||
import {Row} from '../ComponentUtils';
|
||||
import {DropdownField, DropdownFields} from '../DropdownFields';
|
||||
import {InlineErrorBadge} from '../ErrorNotice';
|
||||
import messageBus from '../MessageBus';
|
||||
@ -69,10 +69,10 @@ export default function DebugToolsMenu({dismiss}: {dismiss: () => unknown}) {
|
||||
</DropdownField>
|
||||
<DropdownField title={<T>Server/Client Messages</T>}>
|
||||
<ServerClientMessageLogging />
|
||||
<FlexRow>
|
||||
<Row>
|
||||
<ForceDisconnectButton />
|
||||
<NopOperationButtons />
|
||||
</FlexRow>
|
||||
</Row>
|
||||
</DropdownField>
|
||||
<DropdownField title={<T>Component Explorer</T>}>
|
||||
<ComponentExplorerButton dismiss={dismiss} />
|
||||
@ -97,7 +97,7 @@ function InternalState() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FlexRow>
|
||||
<Row>
|
||||
<Tooltip
|
||||
placement="bottom"
|
||||
title={t(
|
||||
@ -136,9 +136,9 @@ function InternalState() {
|
||||
<T>Clear Persisted State</T>
|
||||
</VSCodeButton>
|
||||
</Tooltip>
|
||||
</FlexRow>
|
||||
</Row>
|
||||
{isDev && (
|
||||
<FlexRow>
|
||||
<Row>
|
||||
<T>Integrate with: </T>
|
||||
<VSCodeCheckbox checked={reduxTools} onChange={() => setReduxTools(v => !v)}>
|
||||
<T>Redux DevTools</T>
|
||||
@ -146,7 +146,7 @@ function InternalState() {
|
||||
<VSCodeCheckbox checked={reactTools} onChange={() => setReactTools(v => !v)}>
|
||||
{t('React <DebugAtoms/>')}
|
||||
</VSCodeCheckbox>
|
||||
</FlexRow>
|
||||
</Row>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {FlexRow, FlexSpacer, ScrollY} from '../../ComponentUtils';
|
||||
import {Row, FlexSpacer, ScrollY} from '../../ComponentUtils';
|
||||
import {Modal} from '../../Modal';
|
||||
import {tracker} from '../../analytics';
|
||||
import {T} from '../../i18n';
|
||||
@ -41,9 +41,9 @@ function LoadedSplitModal() {
|
||||
return (
|
||||
<Modal>
|
||||
<SplitStackEditPanel />
|
||||
<FlexRow style={{padding: 'var(--pad) 0', justifyContent: 'flex-end'}}>
|
||||
<Row style={{padding: 'var(--pad) 0', justifyContent: 'flex-end'}}>
|
||||
<StackEditConfirmButtons />
|
||||
</FlexRow>
|
||||
</Row>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -106,11 +106,11 @@ function LoadedEditStackModal() {
|
||||
{activeTab === 'split' && <SplitStackEditPanel />}
|
||||
</VSCodePanelView>
|
||||
</VSCodePanels>
|
||||
<FlexRow style={{padding: 'var(--pad) 0', justifyContent: 'flex-end'}}>
|
||||
<Row style={{padding: 'var(--pad) 0', justifyContent: 'flex-end'}}>
|
||||
{activeTab === 'split' && <SplitStackToolbar />}
|
||||
<FlexSpacer />
|
||||
<StackEditConfirmButtons />
|
||||
</FlexRow>
|
||||
</Row>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import type {StackEditOpDescription, UseStackEditState} from './stackEditState';
|
||||
|
||||
import {AnimatedReorderGroup} from '../../AnimatedReorderGroup';
|
||||
import {CommitTitle as StandaloneCommitTitle} from '../../CommitTitle';
|
||||
import {FlexRow} from '../../ComponentUtils';
|
||||
import {Row} from '../../ComponentUtils';
|
||||
import {DragHandle} from '../../DragHandle';
|
||||
import {Tooltip} from '../../Tooltip';
|
||||
import {t, T} from '../../i18n';
|
||||
@ -266,7 +266,7 @@ export function StackEditCommit({
|
||||
);
|
||||
|
||||
return (
|
||||
<FlexRow
|
||||
<Row
|
||||
data-reorder-id={onDrag ? commit.key : ''}
|
||||
data-rev={rev}
|
||||
className={`commit${isReorderPreview ? ' commit-reorder-preview' : ''}`}>
|
||||
@ -276,7 +276,7 @@ export function StackEditCommit({
|
||||
{buttons}
|
||||
{title}
|
||||
{rightSideButtons}
|
||||
</FlexRow>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user