11import { Box , Button , Card , Flex , Text } from "@radix-ui/themes" ;
2- import { Suspense , use , useEffect , useState } from "react" ;
2+ import {
3+ Suspense ,
4+ useEffect ,
5+ useState ,
6+ use ,
7+ useRef ,
8+ useImperativeHandle ,
9+ type Ref ,
10+ } from "react" ;
311import { useFetcher , useLoaderData } from "react-router" ;
412import type { loader } from "./board-route" ;
513import { DateTime } from "luxon" ;
614import DynamicForm , {
715 FormSkeleton ,
16+ type DynamicFormRef ,
817 validateDynamicFormSchema ,
918 type DynamicFormValues ,
1019} from "./dynamic-form" ;
@@ -20,7 +29,13 @@ import { parseMarkdownToHtml } from "~/libs/markdown";
2029
2130type Props = { } ;
2231
23- function CardContent ( ) {
32+ interface CardContentRef {
33+ edit : ( ) => void ;
34+ cancel : ( ) => void ;
35+ save : ( ) => void ;
36+ }
37+
38+ function CardContent ( { ref } : { ref : Ref < CardContentRef > } ) {
2439 const {
2540 boardPromise,
2641 standupsPromise,
@@ -33,6 +48,24 @@ function CardContent() {
3348
3449 const schema = validateDynamicFormSchema ( structure ?. schema ) ;
3550
51+ const dynamicFormRef = useRef < DynamicFormRef > ( null ) ;
52+
53+ useImperativeHandle (
54+ ref ,
55+ ( ) => ( {
56+ edit : ( ) => {
57+ handleEditButtonClick ( ) ;
58+ } ,
59+ cancel : ( ) => {
60+ handleDynamicFormCancel ( ) ;
61+ } ,
62+ save : ( ) => {
63+ dynamicFormRef . current ?. submit ( ) ;
64+ } ,
65+ } ) ,
66+ [ ]
67+ ) ;
68+
3669 if ( ! schema ) {
3770 return null ;
3871 }
@@ -111,10 +144,19 @@ function CardContent() {
111144
112145 const [ isEditing , setIsEditing ] = useState ( ! Boolean ( todayStandup ) ) ;
113146
147+ function handleDynamicFormCancel ( ) {
148+ setIsEditing ( false ) ;
149+ }
150+
151+ function handleEditButtonClick ( ) {
152+ setIsEditing ( true ) ;
153+ }
154+
114155 return (
115156 < >
116157 { ! todayStandup && (
117158 < DynamicForm
159+ ref = { dynamicFormRef }
118160 schema = { schema }
119161 onSubmit = { async ( data ) => {
120162 if ( ! structure ) {
@@ -139,6 +181,7 @@ function CardContent() {
139181 { todayStandup &&
140182 ( isEditing ? (
141183 < DynamicForm
184+ ref = { dynamicFormRef }
142185 schema = { schema }
143186 defaultValues = { todayStandup . formData as DynamicFormValues }
144187 onSubmit = { async ( data ) => {
@@ -154,7 +197,7 @@ function CardContent() {
154197 ) ;
155198 setIsEditing ( false ) ;
156199 } }
157- onCancel = { ( ) => setIsEditing ( false ) }
200+ onCancel = { handleDynamicFormCancel }
158201 />
159202 ) : (
160203 < Flex direction = "column" gap = "5" >
@@ -193,7 +236,7 @@ function CardContent() {
193236 highContrast
194237 size = "2"
195238 variant = "surface"
196- onClick = { ( ) => setIsEditing ( true ) }
239+ onClick = { handleEditButtonClick }
197240 >
198241 Edit
199242 </ Button >
@@ -205,16 +248,31 @@ function CardContent() {
205248}
206249
207250function TodaysStandup ( { } : Props ) {
251+ const cardContentRef = useRef < CardContentRef > ( null ) ;
252+
208253 return (
209254 < Card
210255 tabIndex = { 0 }
211256 size = { {
212257 initial : "2" ,
213258 sm : "4" ,
214259 } }
260+ onKeyDown = { ( event ) => {
261+ if ( ( event . metaKey || event . ctrlKey ) && event . key === "Enter" ) {
262+ cardContentRef . current ?. save ( ) ;
263+ }
264+
265+ if ( event . key === "e" ) {
266+ cardContentRef . current ?. edit ( ) ;
267+ }
268+
269+ if ( event . key === "Escape" ) {
270+ cardContentRef . current ?. cancel ( ) ;
271+ }
272+ } }
215273 >
216274 < Suspense fallback = { < FormSkeleton /> } >
217- < CardContent />
275+ < CardContent ref = { cardContentRef } />
218276 </ Suspense >
219277 </ Card >
220278 ) ;
0 commit comments