Skip to content

Commit 640e515

Browse files
committed
✨ Feat: Improve draft form interactions with Floating UI
1 parent 128703e commit 640e515

File tree

7 files changed

+118
-24
lines changed

7 files changed

+118
-24
lines changed

packages/web/src/views/Calendar/components/Event/Draft/GridDraft.tsx

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { FC, MouseEvent } from "react";
2+
import { FloatingFocusManager } from "@floating-ui/react";
23
import { Schema_GridEvent } from "@web/common/types/web.event.types";
34
import { Measurements_Grid } from "@web/views/Calendar/hooks/grid/useGridLayout";
45
import { EventForm } from "@web/views/Forms/EventForm";
@@ -29,7 +30,8 @@ export const GridDraft: FC<Props> = ({
2930
measurements,
3031
weekProps,
3132
}) => {
32-
const { x, y, refs, strategy } = formProps;
33+
const { context, getReferenceProps, getFloatingProps, x, y, refs, strategy } =
34+
formProps;
3335

3436
const onConvert = () => {
3537
const start = weekProps.component.startOfView.format(YEAR_MONTH_DAY_FORMAT);
@@ -65,25 +67,31 @@ export const GridDraft: FC<Props> = ({
6567
}}
6668
ref={refs.setReference}
6769
weekProps={weekProps}
70+
{...getReferenceProps()}
6871
/>
6972

7073
<div>
7174
{draft?.isOpen && (
72-
<StyledFloatContainer
73-
ref={refs.setFloating}
74-
strategy={strategy}
75-
top={y ?? 0}
76-
left={x ?? 0}
77-
>
78-
<EventForm
79-
event={draft}
80-
onClose={draftUtil.discard}
81-
onConvert={onConvert}
82-
onDelete={draftUtil.deleteEvent}
83-
onSubmit={(_draft: Schema_GridEvent) => draftUtil.submit(_draft)}
84-
setEvent={draftUtil.setDraft}
85-
/>
86-
</StyledFloatContainer>
75+
<FloatingFocusManager context={context}>
76+
<StyledFloatContainer
77+
ref={refs.setFloating}
78+
strategy={strategy}
79+
top={y ?? 0}
80+
left={x ?? 0}
81+
{...getFloatingProps()}
82+
>
83+
<EventForm
84+
event={draft}
85+
onClose={draftUtil.discard}
86+
onConvert={onConvert}
87+
onDelete={draftUtil.deleteEvent}
88+
onSubmit={(_draft: Schema_GridEvent) =>
89+
draftUtil.submit(_draft)
90+
}
91+
setEvent={draftUtil.setDraft}
92+
/>
93+
</StyledFloatContainer>
94+
</FloatingFocusManager>
8795
)}
8896
</div>
8997
</>

packages/web/src/views/Calendar/components/Grid/MainGrid/MainGrid.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import mergeRefs from "react-merge-refs";
33
import { Dayjs } from "dayjs";
44
import { Categories_Event } from "@core/types/event.types";
55
import { DRAFT_DURATION_MIN } from "@web/views/Calendar/layout.constants";
6-
import { useAppDispatch } from "@web/store/store.hooks";
6+
import { useAppDispatch, useAppSelector } from "@web/store/store.hooks";
77
import { Ref_Callback } from "@web/common/types/util.types";
88
import { WeekProps } from "@web/views/Calendar/hooks/useWeek";
99
import { DateCalcs } from "@web/views/Calendar/hooks/grid/useDateCalcs";
@@ -23,6 +23,7 @@ import {
2323
} from "./styled";
2424
import { MainGridEvents } from "./MainGridEvents";
2525
import { MainGridColumns } from "../Columns/MainGridColumns";
26+
import { selectIsDrafting } from "@web/ducks/events/selectors/draft.selectors";
2627

2728
interface Props {
2829
dateCalcs: DateCalcs;
@@ -47,10 +48,12 @@ export const MainGrid: FC<Props> = ({
4748

4849
const { component } = weekProps;
4950
const { isCurrentWeek, week, weekDays } = component;
51+
const isDrafting = useAppSelector(selectIsDrafting);
5052

5153
const onMouseDown = async (e: MouseEvent) => {
52-
if (isEventFormOpen()) {
53-
dispatch(draftSlice.actions.discard());
54+
if (isDrafting) {
55+
console.log("moused down while drafting, discarding....");
56+
dispatch(draftSlice.actions.discard({}));
5457
return;
5558
}
5659

packages/web/src/views/Calendar/hooks/draft/actions/useDraftActions.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,14 @@ export const useDraftActions = (
153153
};
154154

155155
const discard = useCallback(() => {
156+
console.log("draft", draft);
156157
if (draft) {
157158
setDraft(null);
158159
}
159160

161+
console.log("discarding ...");
160162
if (reduxDraft || reduxDraftType) {
163+
console.log("discarding redux draft...");
161164
dispatch(draftSlice.actions.discard({}));
162165
}
163166
}, [dispatch, draft, reduxDraft, reduxDraftType]);
@@ -369,7 +372,7 @@ export const useDraftActions = (
369372
const handleChange = useCallback(async () => {
370373
if (!isDrafting) return;
371374

372-
if (activity === "createShortcut" || activity === "gridClick") {
375+
if (activity === "createShortcut") {
373376
await handleShortcutOrClick();
374377
return;
375378
}

packages/web/src/views/Calendar/hooks/draft/effects/useDraftEffects.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,20 @@ export const useDraftEffects = (
4040
}, [dateBeingChanged, isResizing]);
4141

4242
useEffect(() => {
43-
const isStaleDraft = !isDrafting && isFormOpen;
43+
// const isStaleDraft = !isDrafting && (isResizing || isDragging);
44+
const isStaleDraft = !isDrafting;
4445
if (isStaleDraft) {
46+
console.log("setting draft to null");
47+
console.log(state);
4548
setDraft(null);
49+
setIsDragging(false);
50+
setIsFormOpen(false);
51+
setIsResizing(false);
52+
setDragStatus(null);
53+
setResizeStatus(null);
54+
setDateBeingChanged(null);
4655
}
47-
}, [isDrafting, isFormOpen]);
56+
}, [isDrafting]);
4857

4958
useEffect(() => {
5059
handleChange();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { OpenChangeReason } from "@floating-ui/react";
2+
import { useEventForm } from "@web/views/Forms/hooks/useEventForm";
3+
4+
export const useDraftForm = (
5+
isFormOpen: boolean,
6+
reset: () => void,
7+
discard: () => void,
8+
setIsFormOpen: (isOpen: boolean) => void
9+
) => {
10+
const handleDiscard = (reason?: OpenChangeReason) => {
11+
reset();
12+
13+
if (reason === "escape-key") {
14+
console.log("discarding draft cuz escape key was pressed");
15+
discard();
16+
return;
17+
}
18+
19+
if (reason === "outside-press") {
20+
console.log("discarding draft cuz outside press");
21+
discard();
22+
return;
23+
}
24+
};
25+
26+
const onIsFormOpenChange = (isOpen: boolean, reason?: OpenChangeReason) => {
27+
const isFormAlreadyOpen = isFormOpen === true;
28+
console.log("isFormAlreadyOpen", isFormAlreadyOpen);
29+
if (isFormAlreadyOpen) {
30+
// console.log("discarding (local) draft cuz form already open");
31+
handleDiscard(reason);
32+
return;
33+
}
34+
35+
setIsFormOpen(isOpen);
36+
37+
if (isOpen === false) {
38+
console.log("resetting and discarding");
39+
reset();
40+
discard();
41+
}
42+
};
43+
const formProps = useEventForm("grid", isFormOpen, onIsFormOpenChange);
44+
return { formProps };
45+
};

packages/web/src/views/Calendar/hooks/draft/useDraft.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DateCalcs } from "../grid/useDateCalcs";
22
import { WeekProps } from "../useWeek";
33
import { useDraftState } from "./state/useDraftState";
44
import { useDraftActions } from "./actions/useDraftActions";
5+
import { useDraftForm } from "./form/useDraftForm";
56

67
export const useDraft = (
78
dateCalcs: DateCalcs,
@@ -44,10 +45,18 @@ export const useDraft = (
4445
isSidebarOpen
4546
);
4647

48+
const { formProps } = useDraftForm(
49+
isFormOpen,
50+
actions.reset,
51+
actions.discard,
52+
setIsFormOpen
53+
);
54+
4755
return {
4856
draftState: {
4957
draft,
5058
dragStatus,
59+
formProps,
5160
isDragging,
5261
isFormOpen,
5362
isResizing,

packages/web/src/views/Forms/hooks/useEventForm.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ import {
22
autoUpdate,
33
flip,
44
offset,
5+
OpenChangeReason,
56
shift,
7+
useDismiss,
68
useFloating,
79
UseFloatingOptions,
10+
useInteractions,
811
} from "@floating-ui/react";
912

1013
export const useEventForm = (
11-
eventType: "grid" | "sidebarWeek" | "sidebarMonth"
14+
eventType: "grid" | "sidebarWeek" | "sidebarMonth",
15+
isOpen: boolean,
16+
onIsFormOpenChange: (isOpen: boolean, reason?: OpenChangeReason) => void
1217
) => {
1318
let options: Partial<UseFloatingOptions>;
1419

@@ -40,10 +45,22 @@ export const useEventForm = (
4045
};
4146
}
4247

43-
const { context, x, y, refs, strategy } = useFloating(options);
48+
const { context, x, y, refs, strategy } = useFloating({
49+
...options,
50+
open: isOpen,
51+
onOpenChange(newIsOpen, event, reason) {
52+
console.log("onOpenChange", newIsOpen, event, reason);
53+
onIsFormOpenChange(newIsOpen, reason);
54+
},
55+
});
56+
57+
const dismiss = useDismiss(context);
58+
const { getReferenceProps, getFloatingProps } = useInteractions([dismiss]);
4459

4560
return {
4661
context,
62+
getFloatingProps,
63+
getReferenceProps,
4764
refs,
4865
strategy,
4966
x,

0 commit comments

Comments
 (0)