diff --git a/.scaffolding/component.vsc-template.js b/.scaffolding/component.vsc-template.js new file mode 100644 index 0000000..9b074cc --- /dev/null +++ b/.scaffolding/component.vsc-template.js @@ -0,0 +1,152 @@ +(function Template() { + const toPascalCase = (str) => + str + .replace(/(?:^\w|[A-Z]|\b\w)/g, (fl) => fl.toUpperCase()) + .replace(/\W+/g, ''); + + const toCamelCase = (str) => + toPascalCase(str).replace(/^./, (firstLetter) => firstLetter.toLowerCase()); + + return { + userInputs: [ + { + title: 'Component page name', + argumentName: 'name', + defaultValue: 'Sample', + }, + ], + template: [ + { + type: 'folder', + name: (inputs) => `${toPascalCase(inputs.name)}`, + children: [ + { + type: 'file', + name: 'index.ts', + content: (inputs) => `import { ${toPascalCase( + inputs.name + )}, ${toPascalCase( + inputs.name + )}Props } from './${toCamelCase(inputs.name)}'; + +export { ${toPascalCase(inputs.name)} }; +export type { ${toPascalCase(inputs.name)}Props }; + `, + }, + { + type: 'file', + name: (inputs) => `${toCamelCase(inputs.name)}.tsx`, + content: ( + inputs + ) => `import { use${toPascalCase(inputs.name)}Hook } from './${toCamelCase(inputs.name)}.hook'; + +export interface ${toPascalCase(inputs.name)}Props { + data: string; +} + +export function ${toPascalCase(inputs.name)}(props: ${toPascalCase(inputs.name)}Props) { + const { data } = props; + + const { state } = use${toPascalCase(inputs.name)}Hook(props); + return ( +
+

${toPascalCase(inputs.name)}

+ {data} {state} +
+ ); +} +`, + }, + { + type: 'file', + name: (inputs) => `${toCamelCase(inputs.name)}.hook.ts`, + content: (inputs) => `import React from 'react'; + +import { ${toPascalCase(inputs.name)}Props } from './${toCamelCase(inputs.name)}'; + +export function use${toPascalCase(inputs.name)}Hook(props: ${toPascalCase(inputs.name)}Props) { + const { data } = props; + + const [state] = React.useState(data); + + return { + state, + }; +} + +`, + }, + { + type: 'file', + name: (inputs) => `${toCamelCase(inputs.name)}.spec.tsx`, + content: (inputs) => ` +import { + render, + renderHook, + ReturnRenderHookType, + ReturnRenderType, +} from '@testing-react'; +import { clearAllMocks } from '@testing-suit'; + +import { ${toPascalCase(inputs.name)}, ${toPascalCase(inputs.name)}Props } from './${toCamelCase(inputs.name)}'; +import { use${toPascalCase(inputs.name)}Hook } from './${toCamelCase(inputs.name)}.hook'; + +describe('${toPascalCase(inputs.name)}', () => { + beforeEach(() => { + clearAllMocks(); + }); + + describe('render', () => { + let rendered: ReturnRenderType; + + beforeEach(() => { + clearAllMocks(); + }); + + afterEach(() => { + rendered.unmount(); + }); + + it('Should render the view with default props', () => { + // Arrange + + // Act + rendered = render(<${toPascalCase(inputs.name)} data={'0'} />); + + // Assert + expect(rendered.getByText('${toPascalCase(inputs.name)}')); + }); + }); + + describe('hook', () => { + let rendered: ReturnRenderHookType; + + beforeEach(() => { + clearAllMocks(); + }); + + afterEach(() => { + rendered.unmount(); + }); + + it('Should render the hook with default props', () => { + // Arrange + const props: ${toPascalCase(inputs.name)}Props = { + data: 'teste', + }; + + // Act + rendered = renderHook(() => use${toPascalCase(inputs.name)}Hook(props)); + + // Assert + expect(rendered.result.current.state).toEqual('teste'); + }); + }); +}); +`, + }, + ], + }, + ], + }; +}); diff --git a/.scaffolding/page.vsc-template.js b/.scaffolding/page.vsc-template.js index 379cadf..e905269 100644 --- a/.scaffolding/page.vsc-template.js +++ b/.scaffolding/page.vsc-template.js @@ -25,9 +25,9 @@ name: 'index.ts', content: (inputs) => `import { ${toPascalCase( inputs.name - )}Controller } from './controller'; + )} } from './${toCamelCase(inputs.name)}'; -export { ${toPascalCase(inputs.name)}Controller }; +export { ${toPascalCase(inputs.name)} }; `, }, { diff --git a/package.json b/package.json index 0ad60ee..fb50e3f 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", @@ -45,6 +46,7 @@ "axios": "^1.6.8", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "cmdk": "0.2.1", "date-fns": "^3.3.1", "jspdf": "^2.5.1", "lodash": "^4.17.21", @@ -60,6 +62,7 @@ "tailwind-merge": "^2.2.2", "tailwindcss": "^3.4.1", "tailwindcss-animate": "^1.0.7", + "use-debounce": "^10.0.0", "zod": "^3.22.4" }, "devDependencies": { diff --git a/src/app/entities/planningMeal.ts b/src/app/entities/planningMeal.ts index 453cb25..7a506c9 100644 --- a/src/app/entities/planningMeal.ts +++ b/src/app/entities/planningMeal.ts @@ -10,6 +10,7 @@ export interface TMealFood { qty: number; options: []; food: TFood; + name: string; } export interface TMeal { diff --git a/src/app/services/planningMeal/create.ts b/src/app/services/planningMeal/create.ts index 7e559d6..e804c5e 100644 --- a/src/app/services/planningMeal/create.ts +++ b/src/app/services/planningMeal/create.ts @@ -13,6 +13,7 @@ interface TCreatePlanningMeal { time: string; mealFoods: { foodId: string; + name: string; qty: number; measure: { name: string; @@ -43,7 +44,8 @@ function mapper(planningMeal: TCreatePlanningMealDTO): TCreatePlanningMeal { time: meal.time, name: meal.name, mealFoods: meal.mealFoods.map((mealFood) => ({ - foodId: mealFood.id, + foodId: mealFood.foodId, + name: mealFood.name, qty: mealFood.qty, measure: mealFood.measure, options: [], diff --git a/src/app/utils/types.ts b/src/app/utils/types.ts index 37c9940..bd535be 100644 --- a/src/app/utils/types.ts +++ b/src/app/utils/types.ts @@ -19,7 +19,7 @@ export interface PageStatus { /** * Interface que define o retorno inicial de um hook. */ -interface DefaultReturnHookPage { +interface IBaseReturnHook { /** * O status da página, incluindo isLoading, isError e noData. */ @@ -33,4 +33,4 @@ interface DefaultReturnHookPage { * * @template T - Tipo dos outros itens específicos do usuário. */ -export type ReturnHookPage = DefaultReturnHookPage & T; +export type ReturnHookPage = IBaseReturnHook & T; diff --git a/src/view/components/CardMeal/Options.tsx b/src/view/components/CardMeal/Options.tsx index 24162ef..a055478 100644 --- a/src/view/components/CardMeal/Options.tsx +++ b/src/view/components/CardMeal/Options.tsx @@ -19,7 +19,7 @@ export function Options(props: OptionsProps) { className )} > - {mealFood.food.name} - {mealFood.qty} {mealFood.measure.name} + {mealFood.name} - {mealFood.qty} {mealFood.measure.name}
diff --git a/src/view/pages/CreatePlanning/CreatePlanning.hook.ts b/src/view/pages/CreatePlanning/CreatePlanning.hook.ts index 31bcefc..306440c 100644 --- a/src/view/pages/CreatePlanning/CreatePlanning.hook.ts +++ b/src/view/pages/CreatePlanning/CreatePlanning.hook.ts @@ -11,7 +11,7 @@ import * as z from 'zod'; export const CreateMealFoodSchema = z.object({ name: z.string(), - id: z.string().uuid(), + foodId: z.string().uuid(), qty: z.number().min(1), measure: z.object({ name: z.string(), @@ -79,7 +79,7 @@ export function useCreatePlanningHook() { planningMeal: data, }); - toast.success('Plano alimentar criado com sucesso!'); + toast.success('Plano alimentar criado!'); } catch (error) { toast.error('Erro ao criar o plano alimentar'); } finally { @@ -109,7 +109,6 @@ export function useCreatePlanningHook() { ); return { - control, methods, errors, meals: watchMeals, diff --git a/src/view/pages/CreatePlanning/CreatePlanning.tsx b/src/view/pages/CreatePlanning/CreatePlanning.tsx index 5854d30..1564c7a 100644 --- a/src/view/pages/CreatePlanning/CreatePlanning.tsx +++ b/src/view/pages/CreatePlanning/CreatePlanning.tsx @@ -1,7 +1,6 @@ import { Button } from '@godiet-ui/Button'; import { Input } from '@godiet-ui/Input'; -import { DevTool } from '@hookform/devtools'; import { PlusIcon } from '@radix-ui/react-icons'; import { FormProvider } from 'react-hook-form'; @@ -10,7 +9,6 @@ import { useCreatePlanningHook } from './CreatePlanning.hook'; export function CreatePlanning() { const { - control, methods, errors, meals, @@ -23,7 +21,6 @@ export function CreatePlanning() { return ( -

diff --git a/src/view/pages/CreatePlanning/components/CreateMeal/CreateMeal.hook.ts b/src/view/pages/CreatePlanning/components/CreateMeal/CreateMeal.hook.ts index e0b3889..cce16b4 100644 --- a/src/view/pages/CreatePlanning/components/CreateMeal/CreateMeal.hook.ts +++ b/src/view/pages/CreatePlanning/components/CreateMeal/CreateMeal.hook.ts @@ -1,8 +1,12 @@ import { useCallback, useMemo, useReducer, useState } from 'react'; -import { TCreatePlanningMealDTO } from '@godiet-pages/CreatePlanning/CreatePlanning.hook'; +import { + CreateMealFoodSchema, + TCreatePlanningMealDTO, +} from '@godiet-pages/CreatePlanning/CreatePlanning.hook'; import { useFieldArray, useFormContext, useWatch } from 'react-hook-form'; +import * as z from 'zod'; import { CreateMealProps } from './CreateMeal'; @@ -17,6 +21,10 @@ interface FoodsByMeal { name: string; } +type TSelectedFoodToEdit = z.infer & { + mealFoodIndex: number; +}; + export function useCreateMealHook(props: CreateMealProps) { const { mealIndex } = props; @@ -50,12 +58,8 @@ export function useCreateMealHook(props: CreateMealProps) { null ); - const [selectedFoodToEdit, setSelectedFoodToEdit] = useState<{ - id: string; - measure: { name: string; qty: number }; - qty: number; - mealFoodIndex: number; - } | null>(null); + const [selectedFoodToEdit, setSelectedFoodToEdit] = + useState(null); const { register, control } = useFormContext(); @@ -78,7 +82,7 @@ export function useCreateMealHook(props: CreateMealProps) { const initialFoodsByMeal: FoodsByMeal[] = []; watchMeal.mealFoods.forEach((food) => { initialFoodsByMeal.push({ - id: food.id, + id: food.foodId, measure: food.measure, qty: food.qty, prot: 0.6 * 20, @@ -95,7 +99,7 @@ export function useCreateMealHook(props: CreateMealProps) { const generateHashKey = useMemo(() => { if (!selectedFoodToEdit) return 'food-to-edit'; - const hashId = selectedFoodToEdit.id; + const hashId = selectedFoodToEdit.foodId; const hashMeasureName = selectedFoodToEdit.measure.name .trim() .replace(' ', '-'); @@ -120,10 +124,11 @@ export function useCreateMealHook(props: CreateMealProps) { toggleSelectedMealIndex(mealIndex); setSelectedFoodToEdit({ - id: selectedFood.id, + foodId: selectedFood.id, measure: selectedFood.measure, qty: selectedFood.qty, mealFoodIndex: mealFoodIndex, + name: selectedFood.name, }); toggleModalEditFoodOpen(); }, diff --git a/src/view/pages/CreatePlanning/components/CreateMeal/CreateMeal.tsx b/src/view/pages/CreatePlanning/components/CreateMeal/CreateMeal.tsx index 11d06ea..bd4326a 100644 --- a/src/view/pages/CreatePlanning/components/CreateMeal/CreateMeal.tsx +++ b/src/view/pages/CreatePlanning/components/CreateMeal/CreateMeal.tsx @@ -124,10 +124,16 @@ export function CreateMeal(props: CreateMealProps) { - -

- Alimentos selecionados -

+ +
+

+ Alimentos selecionados +

+ + Você pode editar o título dos alimentos selecionados na tabela + abaixo. + +
{ const selectedFood = foods.find( - (foodDatabase) => foodDatabase.id === food.id + (foodDatabase) => foodDatabase.id === food.foodId ); if (!selectedFood) return; const mealFoodCalculated = calculateMealFoods({ - food: selectedFood, + food: { + ...selectedFood, + name: food.name, + }, measure: food.measure, qty: food.qty, }); diff --git a/src/view/pages/CreatePlanning/components/TableFoodsByMeal/TableFoodsByMeal.tsx b/src/view/pages/CreatePlanning/components/TableFoodsByMeal/TableFoodsByMeal.tsx index 62d5dd8..321dac2 100644 --- a/src/view/pages/CreatePlanning/components/TableFoodsByMeal/TableFoodsByMeal.tsx +++ b/src/view/pages/CreatePlanning/components/TableFoodsByMeal/TableFoodsByMeal.tsx @@ -27,6 +27,7 @@ export function TableFoodsByMeal(props: TableFoodsByMealProps) { mealIndex={mealIndex} onOpenModalEdit={onOpenModalEdit} onOpenModalRemove={onOpenModalRemove} + editable /> ) : (
diff --git a/src/view/pages/CreatePlanning/components/TableInfo/TableInfo.tsx b/src/view/pages/CreatePlanning/components/TableInfo/TableInfo.tsx index 26fb308..cbe120f 100644 --- a/src/view/pages/CreatePlanning/components/TableInfo/TableInfo.tsx +++ b/src/view/pages/CreatePlanning/components/TableInfo/TableInfo.tsx @@ -1,5 +1,7 @@ import { useMemo } from 'react'; +import React from 'react'; +import { TCreatePlanningMealDTO } from '@godiet-pages/CreatePlanning/CreatePlanning.hook'; import { Button } from '@godiet-ui/Button'; import { Table, @@ -12,6 +14,7 @@ import { import { cn } from '@godiet-utils/cn'; import { Pencil1Icon, TrashIcon } from '@radix-ui/react-icons'; +import { useFieldArray, useFormContext, useWatch } from 'react-hook-form'; interface openModalEditParams { mealFoodIndex: number; @@ -35,17 +38,39 @@ export interface TableInfoProps { onOpenModalEdit?: (params: openModalEditParams) => void; disabledActions?: boolean; mealFoods: FoodsByMeal[]; + editable?: boolean; } +type HandleChangeInputFunction = ({ + value, + mealFoodIndex, +}: { + value: string; + mealFoodIndex: number; +}) => void; + export function TableInfo(props: TableInfoProps) { const { mealIndex, mealFoods, disabledActions = false, + editable = false, onOpenModalRemove, onOpenModalEdit, } = props; + const { control } = useFormContext(); + + const { update } = useFieldArray({ + name: `meals.${mealIndex}.mealFoods`, + control, + }); + + const watchMealFoods = useWatch({ + control, + name: `meals.${mealIndex}.mealFoods`, + }); + const totalFoods = useMemo(() => { if (mealFoods.length === 0) return []; @@ -88,6 +113,23 @@ export function TableInfo(props: TableInfoProps) { ]; }, [mealFoods]); + const handleChangeInputEditable = + React.useCallback( + (params) => { + const { value, mealFoodIndex } = params; + + const mealFood = watchMealFoods[mealFoodIndex]; + + const mealFoodToUpdate = { + ...mealFood, + name: value, + }; + + update(mealFoodIndex, mealFoodToUpdate); + }, + [watchMealFoods, update] + ); + return ( <> @@ -114,7 +156,23 @@ export function TableInfo(props: TableInfoProps) { return ( - {name} + + {editable ? ( + + handleChangeInputEditable({ + value: event.target.value, + mealFoodIndex: index, + }) + } + /> + ) : ( + name + )} + {qty} {measure.name} diff --git a/src/view/pages/CreatePlanning/components/modals/AddFoodModal/AddFoodModal.hook.ts b/src/view/pages/CreatePlanning/components/modals/AddFoodModal/AddFoodModal.hook.ts index 6b4aaf9..8d9ead3 100644 --- a/src/view/pages/CreatePlanning/components/modals/AddFoodModal/AddFoodModal.hook.ts +++ b/src/view/pages/CreatePlanning/components/modals/AddFoodModal/AddFoodModal.hook.ts @@ -84,7 +84,7 @@ export function useAddFoodModalHook(props: AddFoodModalProps) { name: selectedFood.name, measure: data.measure, qty: data.qty, - id: data.id, + foodId: data.id, }); handleOnCloseModal(); diff --git a/src/view/pages/CreatePlanning/components/modals/AddFoodModal/AddFoodModal.tsx b/src/view/pages/CreatePlanning/components/modals/AddFoodModal/AddFoodModal.tsx index 052224b..dea1514 100644 --- a/src/view/pages/CreatePlanning/components/modals/AddFoodModal/AddFoodModal.tsx +++ b/src/view/pages/CreatePlanning/components/modals/AddFoodModal/AddFoodModal.tsx @@ -1,4 +1,5 @@ import { Button } from '@godiet-ui/Button'; +import { Combobox } from '@godiet-ui/Combobox'; import { Input } from '@godiet-ui/Input'; import { Modal } from '@godiet-ui/Modal'; import { @@ -9,7 +10,6 @@ import { SelectTrigger, SelectValue, } from '@godiet-ui/Select'; -import { SelectAutoComplete } from '@godiet-ui/SelectAutoComplete'; import { Separator } from '@godiet-ui/Separator'; import { Controller } from 'react-hook-form'; @@ -62,7 +62,7 @@ export function AddFoodModal(props: AddFoodModalProps) { control={internalControl} name="id" render={({ field: { value, onChange } }) => ( - ; interface HandleChangeSelectAutoCompleteParams { // eslint-disable-next-line @typescript-eslint/no-explicit-any onChange: (...event: any[]) => void; - event: React.ChangeEvent; + newValue: string; } export function useEditFoodModalHook(props: EditFoodModalProps) { @@ -42,14 +36,16 @@ export function useEditFoodModalHook(props: EditFoodModalProps) { register, reset, setValue, + getValues, formState: { errors, isValid: internalFormIsValid }, control: internalControl, } = useForm({ resolver: zodResolver(CreateMealFoodSchema), defaultValues: { - id: initialValues?.id || '', - measure: initialValues?.measure || '', + foodId: initialValues?.foodId || '', + measure: initialValues?.measure || { name: '' }, qty: initialValues?.qty || 1, + name: initialValues?.name || '', }, }); @@ -57,18 +53,6 @@ export function useEditFoodModalHook(props: EditFoodModalProps) { control: internalControl, }); - const measureOptions = useMemo(() => { - if (!watchFood) return []; - - if (!watchFood.id) return []; - - const selectedFood = foods.find((food) => food.id === watchFood.id); - - if (!selectedFood) return []; - - return selectedFood.measures; - }, [foods, watchFood]); - // Internal Form //External form @@ -86,7 +70,7 @@ export function useEditFoodModalHook(props: EditFoodModalProps) { }, [onClose, reset]); const handleInternalFormSubmit = hookFormSubmit((data) => { - const selectedFood = foods.find((food) => food.id === data.id); + const selectedFood = foods.find((food) => food.id === data.foodId); if (!selectedFood) return; @@ -94,7 +78,7 @@ export function useEditFoodModalHook(props: EditFoodModalProps) { name: selectedFood.name, measure: data.measure, qty: data.qty, - id: data.id, + foodId: data.foodId, }); handleOnCloseModal(); @@ -102,23 +86,26 @@ export function useEditFoodModalHook(props: EditFoodModalProps) { const handleChangeSelectAutoComplete = useCallback( (param: HandleChangeSelectAutoCompleteParams) => { - const { event, onChange } = param; + const { newValue, onChange } = param; - const selectedFood = foods.find( - (food) => food.id === event.target.value - )!; + const selectedFood = foods.find((food) => food.id === newValue)!; + + const formState = getValues(); const hasSameMeasure = selectedFood.measures.find( - (measure) => measure.name === initialValues?.measure.name + (measure) => measure.name === formState.measure?.name ); if (!hasSameMeasure) { setValue('measure', selectedFood.measures[0]); + } else { + setValue('measure', hasSameMeasure); } - onChange(event); + setValue('name', selectedFood.name); + onChange(newValue); }, - [foods, initialValues?.measure, setValue] + [foods, setValue, getValues] ); const foodOptions = useMemo( @@ -126,8 +113,21 @@ export function useEditFoodModalHook(props: EditFoodModalProps) { [foods] ); + const measureOptions = useMemo(() => { + if (!watchFood) return []; + + if (!watchFood.foodId) return []; + + const selectedFood = foods.find((food) => food.id === watchFood.foodId); + + if (!selectedFood) return []; + + return selectedFood.measures; + }, [foods, watchFood]); + const formIsValid = useMemo(() => { return Boolean(internalFormIsValid && watchFood?.measure?.name); + // return true; }, [internalFormIsValid, watchFood?.measure?.name]); return { diff --git a/src/view/pages/CreatePlanning/components/modals/EditFoodModal/EditFoodModal.tsx b/src/view/pages/CreatePlanning/components/modals/EditFoodModal/EditFoodModal.tsx index c288c98..a9fad5b 100644 --- a/src/view/pages/CreatePlanning/components/modals/EditFoodModal/EditFoodModal.tsx +++ b/src/view/pages/CreatePlanning/components/modals/EditFoodModal/EditFoodModal.tsx @@ -1,4 +1,5 @@ import { Button } from '@godiet-ui/Button'; +import { Combobox } from '@godiet-ui/Combobox'; import { Input } from '@godiet-ui/Input'; import { Modal } from '@godiet-ui/Modal'; import { @@ -9,7 +10,6 @@ import { SelectTrigger, SelectValue, } from '@godiet-ui/Select'; -import { SelectAutoComplete } from '@godiet-ui/SelectAutoComplete'; import { Separator } from '@godiet-ui/Separator'; import { Controller } from 'react-hook-form'; @@ -64,17 +64,17 @@ export function EditFoodModal(props: EditFoodModalProps) { > ( - + onChange={(newValue) => handleChangeSelectAutoComplete({ onChange, - event, + newValue, }) } /> @@ -85,38 +85,40 @@ export function EditFoodModal(props: EditFoodModalProps) { ( - { + const selectedMeasure = measureOptions.find( + (measure) => measure.name === event + ); - if (!selectedMeasure) { - onChange(measureOptions[0]); - } + if (!selectedMeasure) { + onChange(measureOptions[0]); + } - onChange(selectedMeasure); - }} - > - - - - - - {measureOptions.map((measure, index) => ( - - {measure.name} - - ))} - - - - )} + onChange(selectedMeasure); + }} + > + + + + + + {measureOptions.map((measure, index) => ( + + {measure.name} + + ))} + + + + ); + }} /> diff --git a/src/view/pages/CreatePlanning/components/modals/SetFavoriteMealModal/SetFavoriteMealModal.hook.ts b/src/view/pages/CreatePlanning/components/modals/SetFavoriteMealModal/SetFavoriteMealModal.hook.ts index 2061ced..fb76eb0 100644 --- a/src/view/pages/CreatePlanning/components/modals/SetFavoriteMealModal/SetFavoriteMealModal.hook.ts +++ b/src/view/pages/CreatePlanning/components/modals/SetFavoriteMealModal/SetFavoriteMealModal.hook.ts @@ -90,6 +90,19 @@ export function useSetFavoriteMealModalHook(props: SetFavoriteMealModalProps) { () => Boolean(selectedFavoriteMeal && selectedFavoriteMeal.length > 0), [selectedFavoriteMeal] ); + + const selectedFavoriteMealToDisplay = useMemo(() => { + const toDisplay = favoritesMeals.find( + (meal) => meal.id === selectedFavoriteMeal + ); + + if (toDisplay) { + return `${toDisplay.name} - ${toDisplay.energy} kcal`; + } + + return null; + }, [favoritesMeals, selectedFavoriteMeal]); + //memos //callbacks @@ -106,14 +119,14 @@ export function useSetFavoriteMealModalHook(props: SetFavoriteMealModalProps) { if (!selectedFavorite) return; const mealFoodsReadyToAdd = selectedFavorite.mealFoods.map((mealFood) => ({ - id: mealFood.food.id, + foodId: mealFood.food.id, measure: mealFood.measure, name: mealFood.food.name, qty: mealFood.qty, })); append(mealFoodsReadyToAdd); - toast.success('Alimentos adicionados com sucesso'); + toast.success('Alimentos adicionados!'); handleCloseModal(); }, [append, favorites, handleCloseModal, selectedFavoriteMeal]); @@ -125,6 +138,7 @@ export function useSetFavoriteMealModalHook(props: SetFavoriteMealModalProps) { isFetchingFavoriteMeal, favoritesMeals, isValid, + selectedFavoriteMealToDisplay, handleCloseModal, setSelectedFavoriteMeal, handleSubmit, diff --git a/src/view/pages/CreatePlanning/components/modals/SetFavoriteMealModal/SetFavoriteMealModal.tsx b/src/view/pages/CreatePlanning/components/modals/SetFavoriteMealModal/SetFavoriteMealModal.tsx index 6458939..fedf48e 100644 --- a/src/view/pages/CreatePlanning/components/modals/SetFavoriteMealModal/SetFavoriteMealModal.tsx +++ b/src/view/pages/CreatePlanning/components/modals/SetFavoriteMealModal/SetFavoriteMealModal.tsx @@ -8,6 +8,7 @@ import { SelectTrigger, SelectValue, } from '@godiet-ui/Select'; +import { Spinner } from '@godiet-ui/Spinner'; import { useSetFavoriteMealModalHook } from './SetFavoriteMealModal.hook'; @@ -26,6 +27,7 @@ export function SetFavoriteMealModal(props: SetFavoriteMealModalProps) { isFetchingFavoriteMeal, favoritesMeals, isValid, + selectedFavoriteMealToDisplay, handleCloseModal, setSelectedFavoriteMeal, handleSubmit, @@ -42,7 +44,11 @@ export function SetFavoriteMealModal(props: SetFavoriteMealModalProps) { - {isErrorFavoriteMeal ? ( + {isFetchingFavoriteMeal ? ( +
+ +
+ ) : isErrorFavoriteMeal ? (

Tivemos um erro para encontrar suas refeições favoritas

Por favor, tente novamente mais tarde!

@@ -62,7 +68,9 @@ export function SetFavoriteMealModal(props: SetFavoriteMealModalProps) { onValueChange={(value) => setSelectedFavoriteMeal(value)} > - + + {selectedFavoriteMealToDisplay} + @@ -71,6 +79,7 @@ export function SetFavoriteMealModal(props: SetFavoriteMealModalProps) { key={option.id} value={option.id} className="flex flex-col items-start" + textValue='option.name + " - " + option.energy + " kcal"' >
{option.name} - {option.energy} kcal diff --git a/src/view/pages/CreatePlanning/components/modals/StarMealModal/StartMealModal.hook.ts b/src/view/pages/CreatePlanning/components/modals/StarMealModal/StartMealModal.hook.ts index 2140372..6d898fe 100644 --- a/src/view/pages/CreatePlanning/components/modals/StarMealModal/StartMealModal.hook.ts +++ b/src/view/pages/CreatePlanning/components/modals/StarMealModal/StartMealModal.hook.ts @@ -60,7 +60,7 @@ export function useStartMealModalHook(props: StarMealModalProps) { const initialFoodsByMeal: FoodsByMeal[] = []; watchMealFoods.forEach((food) => { const selectedFood = foods.find( - (foodDatabase) => foodDatabase.id === food.id + (foodDatabase) => foodDatabase.id === food.foodId ); if (!selectedFood) return; @@ -87,7 +87,7 @@ export function useStartMealModalHook(props: StarMealModalProps) { const handleSubmit = hookFormSubmit(async (data) => { const newMealFoods = watchMealFoods.map((mealFood) => ({ - foodId: mealFood.id, + foodId: mealFood.foodId, measure: mealFood.measure, options: [], qty: mealFood.qty, diff --git a/src/view/pages/FavoritesMeals/components/modals/ModalCreateFavoriteMeal/ModalCreateFavoriteMeal.tsx b/src/view/pages/FavoritesMeals/components/modals/ModalCreateFavoriteMeal/ModalCreateFavoriteMeal.tsx index 47610d4..56ea88d 100644 --- a/src/view/pages/FavoritesMeals/components/modals/ModalCreateFavoriteMeal/ModalCreateFavoriteMeal.tsx +++ b/src/view/pages/FavoritesMeals/components/modals/ModalCreateFavoriteMeal/ModalCreateFavoriteMeal.tsx @@ -1,4 +1,5 @@ import { Button } from '@godiet-ui/Button'; +import { Combobox } from '@godiet-ui/Combobox'; import { Input } from '@godiet-ui/Input'; import { Modal } from '@godiet-ui/Modal'; import { @@ -9,7 +10,6 @@ import { SelectTrigger, SelectValue, } from '@godiet-ui/Select'; -import { SelectAutoComplete } from '@godiet-ui/SelectAutoComplete'; import { Separator } from '@godiet-ui/Separator'; import { SimpleInput } from '@godiet-ui/SimpleInput'; import { Tooltip } from '@godiet-ui/Tooltip'; @@ -79,7 +79,7 @@ export function ModalCreateFavoriteMeal(props: ModalCreateFavoriteMealProps) { control={internalControl} name="foodId" render={({ field: { value, onChange } }) => ( - -
diff --git a/src/view/ui/Combobox/combobox.tsx b/src/view/ui/Combobox/combobox.tsx new file mode 100644 index 0000000..49c9223 --- /dev/null +++ b/src/view/ui/Combobox/combobox.tsx @@ -0,0 +1,135 @@ +import * as React from 'react'; + +import { useControllableState } from '@godiet-hooks/controllable-state'; +import { Button } from '@godiet-ui/Button'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, +} from '@godiet-ui/Command'; +import { Popover, PopoverContent, PopoverTrigger } from '@godiet-ui/Popover'; +import { ScrollArea } from '@godiet-ui/ScrollArea'; +import { Spinner } from '@godiet-ui/Spinner'; +import { cn } from '@godiet-utils/cn'; + +import { CaretSortIcon, CheckIcon } from '@radix-ui/react-icons'; + +interface OptionType { + label: string; + value: string; +} +interface ComboboxProps { + options: Array<{ value: string; label: string }>; + value?: string; + onChange?: (value: string) => void; + isLoading?: boolean; + placeholder?: string; + emptyMessage?: string; +} + +interface FilterFunction { + (value: string, search: string): number; +} + +export function Combobox(props: ComboboxProps) { + const { options, value, onChange, isLoading, emptyMessage, placeholder } = + props; + const [open, setOpen] = React.useState(false); + + const [internalValue, setInternalValue] = useControllableState({ + defaultValue: '', + value, + onChange, + }); + + const handleFilterCommand = React.useCallback( + (value, search) => + value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0, + [] + ); + + const handleSelectCommandItem = React.useCallback( + (currentValue: string, option: OptionType) => { + setInternalValue(currentValue === option.label ? '' : option.value); + + setOpen(false); + }, + [setInternalValue] + ); + + const defaultPlaceholder = React.useMemo( + () => placeholder || 'Selecione uma opção', + [placeholder] + ); + + const defaultEmptyMessage = React.useMemo( + () => emptyMessage || 'Nenhuma opção encontrada.', + [emptyMessage] + ); + + const defaultLabel = React.useMemo( + () => options.find((option) => option.value === internalValue)?.label, + [internalValue, options] + ); + + return ( + { + if (isLoading) return; + + setOpen((prev) => !prev); + }} + modal={true} + > + + + + + + + + + + {defaultEmptyMessage} + + {options.map((option) => ( + + handleSelectCommandItem(currentValue, option) + } + value={option.label} + > + + + {option.label} + + ))} + + + + + + ); +} diff --git a/src/view/ui/Combobox/index.ts b/src/view/ui/Combobox/index.ts new file mode 100644 index 0000000..36dd8c5 --- /dev/null +++ b/src/view/ui/Combobox/index.ts @@ -0,0 +1 @@ +export * from './combobox'; diff --git a/src/view/ui/Command/command.tsx b/src/view/ui/Command/command.tsx new file mode 100644 index 0000000..8df6acc --- /dev/null +++ b/src/view/ui/Command/command.tsx @@ -0,0 +1,164 @@ +import * as React from 'react'; + +import { ModalContent, ModalRoot } from '@godiet-ui/Modal'; +import { cn } from '@godiet-utils/cn'; + +import { type DialogProps } from '@radix-ui/react-dialog'; +import { MagnifyingGlassIcon } from '@radix-ui/react-icons'; +import { Command as CommandPrimitive } from 'cmdk'; + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +Command.displayName = CommandPrimitive.displayName; + +interface CommandDialogProps extends DialogProps {} + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + + + + {children} + + + + ); +}; + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + // eslint-disable-next-line react/no-unknown-property +
+ + + +
+)); + +CommandInput.displayName = CommandPrimitive.Input.displayName; + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandList.displayName = CommandPrimitive.List.displayName; + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName; + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandGroup.displayName = CommandPrimitive.Group.displayName; + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandSeparator.displayName = CommandPrimitive.Separator.displayName; + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandItem.displayName = CommandPrimitive.Item.displayName; + +const CommandShortcut = ({ + className, + + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; + +CommandShortcut.displayName = 'CommandShortcut'; + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +}; diff --git a/src/view/ui/Command/index.ts b/src/view/ui/Command/index.ts new file mode 100644 index 0000000..b3e7a50 --- /dev/null +++ b/src/view/ui/Command/index.ts @@ -0,0 +1 @@ +export * from './command'; diff --git a/src/view/ui/Modal/index.ts b/src/view/ui/Modal/index.ts index d377d08..5331277 100644 --- a/src/view/ui/Modal/index.ts +++ b/src/view/ui/Modal/index.ts @@ -14,4 +14,6 @@ export const Modal = { Description: ModalDescription, }; +export { ModalContent, ModalRoot } from './Modal'; + export type { ModalProps } from './Modal'; diff --git a/src/view/ui/ScrollArea/index.ts b/src/view/ui/ScrollArea/index.ts new file mode 100644 index 0000000..cb8dbd1 --- /dev/null +++ b/src/view/ui/ScrollArea/index.ts @@ -0,0 +1 @@ +export * from './scroll-area'; diff --git a/src/view/ui/ScrollArea/scroll-area.tsx b/src/view/ui/ScrollArea/scroll-area.tsx new file mode 100644 index 0000000..800863c --- /dev/null +++ b/src/view/ui/ScrollArea/scroll-area.tsx @@ -0,0 +1,54 @@ +import * as React from 'react'; + +import { cn } from '@godiet-utils/cn'; + +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + + + +)); + +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = 'vertical', ...props }, ref) => ( + + + +)); + +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; + +export { ScrollArea, ScrollBar }; diff --git a/yarn.lock b/yarn.lock index 1cb86a6..27e8403 100644 --- a/yarn.lock +++ b/yarn.lock @@ -702,6 +702,13 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/primitive@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.0.tgz#e1d8ef30b10ea10e69c76e896f608d9276352253" + integrity sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd" @@ -754,6 +761,13 @@ "@radix-ui/react-primitive" "1.0.3" "@radix-ui/react-slot" "1.0.2" +"@radix-ui/react-compose-refs@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz#37595b1f16ec7f228d698590e78eeed18ff218ae" + integrity sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" @@ -761,6 +775,13 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-context@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.0.tgz#f38e30c5859a9fb5e9aa9a9da452ee3ed9e0aee0" + integrity sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-context@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c" @@ -768,6 +789,27 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-dialog@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.0.tgz#997e97cb183bc90bd888b26b8e23a355ac9fe5f0" + integrity sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.0" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-context" "1.0.0" + "@radix-ui/react-dismissable-layer" "1.0.0" + "@radix-ui/react-focus-guards" "1.0.0" + "@radix-ui/react-focus-scope" "1.0.0" + "@radix-ui/react-id" "1.0.0" + "@radix-ui/react-portal" "1.0.0" + "@radix-ui/react-presence" "1.0.0" + "@radix-ui/react-primitive" "1.0.0" + "@radix-ui/react-slot" "1.0.0" + "@radix-ui/react-use-controllable-state" "1.0.0" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.4" + "@radix-ui/react-dialog@^1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300" @@ -796,6 +838,18 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-dismissable-layer@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.0.tgz#35b7826fa262fd84370faef310e627161dffa76b" + integrity sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.0" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-primitive" "1.0.0" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-escape-keydown" "1.0.0" + "@radix-ui/react-dismissable-layer@1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4" @@ -822,6 +876,13 @@ "@radix-ui/react-primitive" "1.0.3" "@radix-ui/react-use-controllable-state" "1.0.1" +"@radix-ui/react-focus-guards@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz#339c1c69c41628c1a5e655f15f7020bf11aa01fa" + integrity sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-focus-guards@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad" @@ -829,6 +890,16 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-focus-scope@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.0.tgz#95a0c1188276dc8933b1eac5f1cdb6471e01ade5" + integrity sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-primitive" "1.0.0" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-focus-scope@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525" @@ -844,6 +915,14 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-icons/-/react-icons-1.3.0.tgz#c61af8f323d87682c5ca76b856d60c2312dbcb69" integrity sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw== +"@radix-ui/react-id@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.0.tgz#8d43224910741870a45a8c9d092f25887bb6d11e" + integrity sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.0" + "@radix-ui/react-id@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0" @@ -937,6 +1016,14 @@ "@radix-ui/react-use-size" "1.0.1" "@radix-ui/rect" "1.0.1" +"@radix-ui/react-portal@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.0.tgz#7220b66743394fabb50c55cb32381395cc4a276b" + integrity sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.0" + "@radix-ui/react-portal@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15" @@ -945,6 +1032,15 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.3" +"@radix-ui/react-presence@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.0.tgz#814fe46df11f9a468808a6010e3f3ca7e0b2e84a" + integrity sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-use-layout-effect" "1.0.0" + "@radix-ui/react-presence@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba" @@ -954,6 +1050,14 @@ "@radix-ui/react-compose-refs" "1.0.1" "@radix-ui/react-use-layout-effect" "1.0.1" +"@radix-ui/react-primitive@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz#376cd72b0fcd5e0e04d252ed33eb1b1f025af2b0" + integrity sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-slot" "1.0.0" + "@radix-ui/react-primitive@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0" @@ -978,6 +1082,22 @@ "@radix-ui/react-use-callback-ref" "1.0.1" "@radix-ui/react-use-controllable-state" "1.0.1" +"@radix-ui/react-scroll-area@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.0.5.tgz#01160c6893f24a2ddb5aa399ae5b3ba84ad4d3cc" + integrity sha512-b6PAgH4GQf9QEn8zbT2XUHpW5z8BzqEc7Kl11TwDrvuTrxlkcjTD5qa/bxgKr+nmuXKu4L/W5UZ4mlP/VG/5Gw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/number" "1.0.1" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-select@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-2.0.0.tgz#a3511792a51a7018d6559357323a7f52e0e38887" @@ -1014,6 +1134,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.3" +"@radix-ui/react-slot@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.0.tgz#7fa805b99891dea1e862d8f8fbe07f4d6d0fd698" + integrity sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-slot@1.0.2", "@radix-ui/react-slot@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" @@ -1065,6 +1193,13 @@ "@radix-ui/react-use-controllable-state" "1.0.1" "@radix-ui/react-visually-hidden" "1.0.3" +"@radix-ui/react-use-callback-ref@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz#9e7b8b6b4946fe3cbe8f748c82a2cce54e7b6a90" + integrity sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a" @@ -1072,6 +1207,14 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-use-controllable-state@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz#a64deaafbbc52d5d407afaa22d493d687c538b7f" + integrity sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-controllable-state@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286" @@ -1080,6 +1223,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-callback-ref" "1.0.1" +"@radix-ui/react-use-escape-keydown@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.0.tgz#aef375db4736b9de38a5a679f6f49b45a060e5d1" + integrity sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-escape-keydown@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz#217b840c250541609c66f67ed7bab2b733620755" @@ -1088,6 +1239,13 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-callback-ref" "1.0.1" +"@radix-ui/react-use-layout-effect@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz#2fc19e97223a81de64cd3ba1dc42ceffd82374dc" + integrity sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399" @@ -2499,6 +2657,13 @@ clsx@^2.1.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== +cmdk@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/cmdk/-/cmdk-0.2.1.tgz#aa8e1332bb0b8d8484e793017c82537351188d9a" + integrity sha512-U6//9lQ6JvT47+6OF6Gi8BvkxYQ8SCRRSKIJkthIMsFsLZRG0cKvTtuTaefyIKMQb8rvvXy0wGdpTNq/jPtm+g== + dependencies: + "@radix-ui/react-dialog" "1.0.0" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -5353,6 +5518,17 @@ react-remove-scroll-bar@^2.3.3: react-style-singleton "^2.2.1" tslib "^2.0.0" +react-remove-scroll@2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz#afe6491acabde26f628f844b67647645488d2ea0" + integrity sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA== + dependencies: + react-remove-scroll-bar "^2.3.3" + react-style-singleton "^2.2.1" + tslib "^2.1.0" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" + react-remove-scroll@2.5.5: version "2.5.5" resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77" @@ -6414,6 +6590,11 @@ use-callback-ref@^1.3.0: dependencies: tslib "^2.0.0" +use-debounce@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-10.0.0.tgz#5091b18d6c16292605f588bae3c0d2cfae756ff2" + integrity sha512-XRjvlvCB46bah9IBXVnq/ACP2lxqXyZj0D9hj4K5OzNroMDpTEBg8Anuh1/UfRTRs7pLhQ+RiNxxwZu9+MVl1A== + use-deep-compare-effect@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/use-deep-compare-effect/-/use-deep-compare-effect-1.8.1.tgz#ef0ce3b3271edb801da1ec23bf0754ef4189d0c6"