Skip to content

Commit 25427e3

Browse files
authored
Merge pull request #13330 from gitbutlerapp/push-mwtkwnzssxlm
Lite: misc
2 parents 5be0f2e + 15a2812 commit 25427e3

8 files changed

Lines changed: 101 additions & 70 deletions

File tree

apps/lite/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"@atlaskit/pragmatic-drag-and-drop": "^1.7.9",
3939
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
4040
"@base-ui/react": "^1.4.0",
41+
"@base-ui/utils": "^0.2.7",
4142
"@gitbutler/but-sdk": "workspace:*",
4243
"@pierre/diffs": "^1.1.3",
4344
"@reduxjs/toolkit": "catalog:redux",

apps/lite/ui/src/native-menu.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ export const showNativeContextMenu = async (
7272
? getBottomLeft(event.currentTarget)
7373
: {
7474
x: Math.round(event.clientX),
75-
y: Math.round(event.clientY),
75+
// Position just below the cursor so the first item is not hovered on
76+
// open.
77+
y: Math.round(event.clientY) + 1,
7678
};
7779

7880
await showNativeMenu(items, position);

apps/lite/ui/src/routes/project/$id/ProjectPreviewLayout.tsx

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import { Dialog } from "@base-ui/react";
22
import { FC, ReactNode, use, useState } from "react";
33
import { Group, Panel, Separator, useDefaultLayout } from "react-resizable-panels";
44
import { ShortcutButton } from "#ui/ShortcutButton.tsx";
5-
import { isPreviewPanelVisible, Panel as PanelType } from "#ui/routes/project/$id/state/layout.ts";
5+
import { classes } from "#ui/classes.ts";
6+
import {
7+
getFocus,
8+
isPreviewPanelVisible,
9+
Panel as PanelType,
10+
} from "#ui/routes/project/$id/state/layout.ts";
611
import {
712
projectActions,
813
selectProjectLayoutState,
@@ -26,6 +31,9 @@ export const ProjectPreviewLayout: FC<{
2631
const panelIds: Array<PanelType> = isPreviewPanelVisible(layoutState)
2732
? ["primary", "preview"]
2833
: ["primary"];
34+
const focus = getFocus(layoutState);
35+
const focusPrimary = () => dispatch(projectActions.focusPrimary({ projectId }));
36+
const focusPreview = () => dispatch(projectActions.focusPreview({ projectId }));
2937
const { defaultLayout, onLayoutChanged } = useDefaultLayout({
3038
id: `project:${projectId}:layout`,
3139
panelIds,
@@ -47,7 +55,12 @@ export const ProjectPreviewLayout: FC<{
4755
<Panel
4856
id={"primary" satisfies PanelType}
4957
minSize={400}
50-
className={sharedStyles.primaryPanel}
58+
onPointerDown={focusPrimary}
59+
className={classes(
60+
sharedStyles.panel,
61+
sharedStyles.primaryPanel,
62+
focus === "primary" && sharedStyles.focusedPanel,
63+
)}
5164
>
5265
{children}
5366
</Panel>
@@ -58,7 +71,12 @@ export const ProjectPreviewLayout: FC<{
5871
id={"preview" satisfies PanelType}
5972
minSize={300}
6073
defaultSize="70%"
61-
className={sharedStyles.previewPanel}
74+
onPointerDown={focusPreview}
75+
className={classes(
76+
sharedStyles.panel,
77+
sharedStyles.previewPanel,
78+
focus === "preview" && sharedStyles.focusedPanel,
79+
)}
6280
>
6381
{
6482
// There can only be one user of the ref at a time.

apps/lite/ui/src/routes/project/$id/shared.module.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@
1818
padding: var(--panel-padding);
1919
}
2020

21+
.panel {
22+
border-bottom: 2px solid transparent;
23+
}
24+
25+
.focusedPanel {
26+
border-bottom-color: var(--color-black);
27+
}
28+
2129
.previewDialogPopup {
2230
display: flex;
2331
position: fixed;

apps/lite/ui/src/routes/project/$id/workspace/OperationTooltip.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,12 @@ export const OperationTooltip: FC<
3232
const isSource = source && operationSourceMatchesItem(source, item);
3333

3434
const tooltip = enabled ? (
35-
isSource ? (
36-
<>Select a target</>
37-
) : operation ? (
38-
controls ? (
35+
<>
36+
{isSource ? <>Select a target</> : operation ? operationLabel(operation) : null}
37+
{controls && (
3938
<>
4039
<button type="button" className={uiStyles.button} onClick={controls.onConfirm}>
41-
{operationLabel(operation)}
40+
Confirm
4241
</button>
4342
<button
4443
type="button"
@@ -49,10 +48,8 @@ export const OperationTooltip: FC<
4948
Cancel
5049
</button>
5150
</>
52-
) : (
53-
<>{operationLabel(operation)}</>
54-
)
55-
) : null
51+
)}
52+
</>
5653
) : null;
5754

5855
const trigger = useRender({ render, props });

apps/lite/ui/src/routes/project/$id/workspace/route.module.css

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,16 @@
121121

122122
.previewHunk {
123123
padding: 4px 6px;
124+
border: 2px solid transparent;
125+
border-radius: 8px;
124126

125127
&:where(:hover) {
126-
outline: 2px solid var(--color-separator);
128+
border-color: var(--color-separator);
127129
}
128130
}
129131

130132
.previewHunkSelected {
131-
outline: 2px solid light-dark(black, white);
133+
border-color: light-dark(black, white);
132134
}
133135

134136
.segments {

apps/lite/ui/src/routes/project/$id/workspace/route.tsx

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import {
6464
} from "#ui/native-menu.ts";
6565
import uiStyles from "#ui/ui.module.css";
6666
import { mergeProps, Tooltip, useRender } from "@base-ui/react";
67+
import { useMergedRefs } from "@base-ui/utils/useMergedRefs";
6768
import {
6869
AbsorptionTarget,
6970
Commit,
@@ -265,8 +266,9 @@ const ItemRow: FC<
265266
{
266267
isSelected?: boolean;
267268
} & ComponentProps<"div">
268-
> = ({ className, isSelected, ...props }) => {
269+
> = ({ className, isSelected, ref: refProp, ...props }) => {
269270
const rowRef = useRef<HTMLDivElement | null>(null);
271+
const mergedRef = useMergedRefs(rowRef, refProp);
270272

271273
useLayoutEffect(() => {
272274
if (!isSelected) return;
@@ -279,7 +281,7 @@ const ItemRow: FC<
279281
return (
280282
<div
281283
{...props}
282-
ref={rowRef}
284+
ref={mergedRef}
283285
className={classes(className, styles.itemRow, isSelected && styles.itemRowSelected)}
284286
/>
285287
);
@@ -830,34 +832,33 @@ const EditorHelp: FC<{
830832
const InlineCommitMessageEditor: FC<{
831833
message: string;
832834
onSubmit: (value: string) => void;
833-
onCancel: () => void;
835+
onExit: () => void;
834836
formRef?: Ref<HTMLFormElement>;
835-
}> = ({ message, onSubmit, onCancel, formRef }) => (
836-
<form
837-
ref={formRef}
838-
className={styles.editorForm}
839-
onSubmit={(event) => {
840-
event.preventDefault();
841-
const formData = new FormData(event.currentTarget);
842-
onCancel();
843-
onSubmit(formData.get("message") as string);
844-
}}
845-
>
846-
<textarea
847-
ref={(el) => {
848-
if (!el) return;
849-
el.focus();
850-
const cursorPosition = el.value.length;
851-
el.setSelectionRange(cursorPosition, cursorPosition);
852-
}}
853-
aria-label="Commit message"
854-
name="message"
855-
defaultValue={message.trim()}
856-
className={classes(styles.editorInput, styles.editCommitMessageInput)}
857-
/>
858-
<EditorHelp bindings={rewordCommitBindings} />
859-
</form>
860-
);
837+
}> = ({ message, onSubmit, onExit, formRef }) => {
838+
const submit = (event: React.SyntheticEvent<HTMLFormElement>) => {
839+
event.preventDefault();
840+
const formData = new FormData(event.currentTarget);
841+
onExit();
842+
onSubmit(formData.get("message") as string);
843+
};
844+
return (
845+
<form ref={formRef} className={styles.editorForm} onSubmit={submit} onBlur={submit}>
846+
<textarea
847+
ref={(el) => {
848+
if (!el) return;
849+
el.focus();
850+
const cursorPosition = el.value.length;
851+
el.setSelectionRange(cursorPosition, cursorPosition);
852+
}}
853+
aria-label="Commit message"
854+
name="message"
855+
defaultValue={message.trim()}
856+
className={classes(styles.editorInput, styles.editCommitMessageInput)}
857+
/>
858+
<EditorHelp bindings={rewordCommitBindings} />
859+
</form>
860+
);
861+
};
861862

862863
const CommitRow: FC<
863864
{
@@ -1007,7 +1008,7 @@ const CommitRow: FC<
10071008
formRef={commitMessageFormRef}
10081009
message={optimisticMessage}
10091010
onSubmit={saveNewMessage}
1010-
onCancel={endEditing}
1011+
onExit={endEditing}
10111012
/>
10121013
) : (
10131014
<>
@@ -1444,31 +1445,30 @@ const InlineBranchNameEditor: FC<{
14441445
onSubmit: (value: string) => void;
14451446
onExit: () => void;
14461447
formRef?: Ref<HTMLFormElement>;
1447-
}> = ({ branchName, onSubmit, onExit, formRef }) => (
1448-
<form
1449-
ref={formRef}
1450-
className={styles.editorForm}
1451-
onSubmit={(event) => {
1452-
event.preventDefault();
1453-
const formData = new FormData(event.currentTarget);
1454-
onExit();
1455-
onSubmit(formData.get("branchName") as string);
1456-
}}
1457-
>
1458-
<input
1459-
aria-label="Branch name"
1460-
ref={(el) => {
1461-
if (!el) return;
1462-
el.focus();
1463-
el.select();
1464-
}}
1465-
name="branchName"
1466-
defaultValue={branchName}
1467-
className={classes(styles.editorInput, styles.renameBranchInput)}
1468-
/>
1469-
<EditorHelp bindings={renameBranchBindings} />
1470-
</form>
1471-
);
1448+
}> = ({ branchName, onSubmit, onExit, formRef }) => {
1449+
const submit = (event: React.SyntheticEvent<HTMLFormElement>) => {
1450+
event.preventDefault();
1451+
const formData = new FormData(event.currentTarget);
1452+
onExit();
1453+
onSubmit(formData.get("branchName") as string);
1454+
};
1455+
return (
1456+
<form ref={formRef} className={styles.editorForm} onSubmit={submit} onBlur={submit}>
1457+
<input
1458+
aria-label="Branch name"
1459+
ref={(el) => {
1460+
if (!el) return;
1461+
el.focus();
1462+
el.select();
1463+
}}
1464+
name="branchName"
1465+
defaultValue={branchName}
1466+
className={classes(styles.editorInput, styles.renameBranchInput)}
1467+
/>
1468+
<EditorHelp bindings={renameBranchBindings} />
1469+
</form>
1470+
);
1471+
};
14721472

14731473
const SegmentRow: FC<
14741474
{

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)