diff --git a/apps/ui-playground/app/components/render.tsx b/apps/ui-playground/app/components/render.tsx index 652a80e84b..10f0437ecc 100644 --- a/apps/ui-playground/app/components/render.tsx +++ b/apps/ui-playground/app/components/render.tsx @@ -24,7 +24,7 @@ export const RenderComponentWithSnippet: React.FC> = (p // }, // }); return ( -
+
{props.children}
diff --git a/apps/ui-playground/content/design/components/section.basic.tsx b/apps/ui-playground/content/design/components/section.basic.tsx new file mode 100644 index 0000000000..5563890e15 --- /dev/null +++ b/apps/ui-playground/content/design/components/section.basic.tsx @@ -0,0 +1,58 @@ +"use client"; + +import { RenderComponentWithSnippet } from "@/app/components/render"; +import { useState } from "react"; + +import { Switch } from "@calcom/ui/components/form"; +import { Section } from "@calcom/ui/components/section"; + +export const BasicExample = () => { + const [isOpen, setIsOpen] = useState(true); + + return ( + +
+ + + + {isOpen && ( + +

This is the main content of the section.

+
+ )} +
+
+ ); +}; + +export const BasicExampleSnippet = ` +"use client"; + +import { useState } from "react"; +import { Section } from "@calcom/ui/components/section"; +import { Switch } from "@calcom/ui/components/form"; + +const BasicSection = () => { + const [isOpen, setIsOpen] = useState(true); + + return ( +
+ + + + + + {isOpen && ( + +

This is the main content of the section.

+
+ )} +
+ ); +}; +`; diff --git a/apps/ui-playground/content/design/components/section.mdx b/apps/ui-playground/content/design/components/section.mdx new file mode 100644 index 0000000000..b98257cf2d --- /dev/null +++ b/apps/ui-playground/content/design/components/section.mdx @@ -0,0 +1,40 @@ +--- +title: Section +--- +import { Section } from "@calcom/ui/components/section" +import { RenderComponentWithSnippet } from "@/app/components/render" +import { Row } from "@/app/components/row" +import { BasicExample } from "./section.basic" +import { WithIconExample } from "./section.withIcon" +import { SubSectionExample } from "./section.subsection" + +## Basic Usage + +The Section component provides a structured way to organize content with a consistent visual hierarchy. It includes several subcomponents for different parts of the section. + + + +## With Icon + +Sections can include an icon in the header to provide visual context. + + + +## SubSections + +Sections can contain subsections for organizing related content in a nested structure. + + + +## Components + +The Section component is composed of several subcomponents: + +- `Section` - The root container +- `Section.Header` - Container for the section header +- `Section.Title` - The section title +- `Section.Description` - Optional description text +- `Section.Content` - The main content area +- `Section.SubSection` - A nested section +- `Section.SubSectionHeader` - Header for a subsection +- `Section.SubSectionContent` - Content area for a subsection diff --git a/apps/ui-playground/content/design/components/section.subsection.tsx b/apps/ui-playground/content/design/components/section.subsection.tsx new file mode 100644 index 0000000000..dbb461880d --- /dev/null +++ b/apps/ui-playground/content/design/components/section.subsection.tsx @@ -0,0 +1,151 @@ +"use client"; + +import { RenderComponentWithSnippet } from "@/app/components/render"; +import { useState } from "react"; + +import { Input, Switch } from "@calcom/ui/components/form"; +import { Section } from "@calcom/ui/components/section"; + +export const SubSectionExample = () => { + const [isMainOpen, setIsMainOpen] = useState(true); + const [isFirstSubsectionOpen, setIsFirstSubsectionOpen] = useState(true); + const [isSecondSubsectionOpen, setIsSecondSubsectionOpen] = useState(true); + + return ( + +
+ + + + {isMainOpen && ( + + + + + + + + + + + {isFirstSubsectionOpen && ( + +

This is the content of the first subsection.

+
+ )} +
+ + + + + {isSecondSubsectionOpen && ( + +
+
Field Name
+
Field Type
+
Value
+
When to Write
+
+ +
+ + + + +
+
+
+ )} +
+
+ )} +
+
+ ); +}; + +export const SubSectionExampleSnippet = ` +"use client"; + +import { useState } from "react"; +import { Section } from "@calcom/ui/components/section"; +import { Switch } from "@calcom/ui/components/form"; + +const SectionWithSubsections = () => { + const [isMainOpen, setIsMainOpen] = useState(true); + const [isFirstSubsectionOpen, setIsFirstSubsectionOpen] = useState(true); + const [isSecondSubsectionOpen, setIsSecondSubsectionOpen] = useState(true); + + return ( +
+ + + + {isMainOpen && ( + + + + + + + + + + + {isFirstSubsectionOpen && ( + +

This is the content of the first subsection.

+
+ )} +
+ + + + + {isSecondSubsectionOpen && ( + +
+
Field Name
+
Field Type
+
Value
+
When to Write
+
+ +
+ + + + +
+
+
+ )} +
+
+ )} +
+ ); +}; +`; diff --git a/apps/ui-playground/content/design/components/section.withIcon.tsx b/apps/ui-playground/content/design/components/section.withIcon.tsx new file mode 100644 index 0000000000..7e1e032630 --- /dev/null +++ b/apps/ui-playground/content/design/components/section.withIcon.tsx @@ -0,0 +1,63 @@ +"use client"; + +import { RenderComponentWithSnippet } from "@/app/components/render"; +import { useState } from "react"; + +import { Switch } from "@calcom/ui/components/form"; +import { Section } from "@calcom/ui/components/section"; + +export const WithIconExample = () => { + const [isOpen, setIsOpen] = useState(true); + + return ( + +
+ + + + {isOpen && ( + +

+ This section demonstrates how to include an icon in the header and uses FormKit auto-animate for + smooth transitions when toggling content visibility. +

+
+ )} +
+
+ ); +}; + +export const WithIconExampleSnippet = ` +"use client"; + +import { useState } from "react"; +import { Section } from "@calcom/ui/components/section"; +import { Switch } from "@calcom/ui/components/form"; + +const SectionWithIcon = () => { + const [isOpen, setIsOpen] = useState(true); + + return ( +
+ + + + {isOpen && ( + +

+ This section demonstrates how to include an icon in the header and uses FormKit auto-animate for + smooth transitions when toggling content visibility. +

+
+ )} +
+ ); +}; +`; diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index fad82aff6e..acd15b9251 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -2812,6 +2812,7 @@ "salesforce_skip_entry_creation": "Skip creating {{entry}} record if they do not exist in Salesforce", "salesforce_if_account_does_not_exist": "If the contact does not exist under an account, create new lead from attendee", "salesforce_create_new_contact_under_account": "Create a new contact under an account based on email domain of attendee and existing contacts", + "salesforce_change_record_owner_on_booking":"Change record owner on booking", "mass_assign_attributes": "Mass assign attributes", "reroute_preview_custom_message": "It results in showing custom message. Try changing the response to route to an event", "reroute_preview_external_redirect": "It results in redirecting to {{externalUrl}}. Try changing the response to route to an event", @@ -2908,6 +2909,7 @@ "routing_form_insights_assignment_reason": "Assignment Reason", "access_denied": "Access Denied", "salesforce_route_to_owner": "Contact owner will be the Round Robin host if available", + "salesforce_add_attendees_as":"Add new attendees as", "salesforce_do_not_route_to_owner": "Contact owner will not be forced (can still be host if it matches the attributes and Round Robin criteria)", "salesforce_route_to_custom_lookup_field": "Route to a user that matches a lookup field on an account", "salesforce_option": "Salesforce Option", diff --git a/packages/app-store/_components/AppCard.tsx b/packages/app-store/_components/AppCard.tsx index 1aebf7f5fc..3033a1bd8d 100644 --- a/packages/app-store/_components/AppCard.tsx +++ b/packages/app-store/_components/AppCard.tsx @@ -5,12 +5,11 @@ import { useTranslation } from "react-i18next"; import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import { useIsPlatform } from "@calcom/atoms/hooks/useIsPlatform"; import type { RouterOutputs } from "@calcom/trpc/react"; -import { Switch } from "@calcom/ui/components/form"; -import { Badge } from "@calcom/ui/components/badge"; -import { Icon } from "@calcom/ui/components/icon"; -import { Avatar } from "@calcom/ui/components/avatar"; -import { Button } from "@calcom/ui/components/button"; import classNames from "@calcom/ui/classNames"; +import { Button } from "@calcom/ui/components/button"; +import { Switch } from "@calcom/ui/components/form"; +import { Icon } from "@calcom/ui/components/icon"; +import { Section } from "@calcom/ui/components/section"; import type { CredentialOwner } from "../types"; import OmniInstallAppButton from "./OmniInstallAppButton"; @@ -49,45 +48,36 @@ export default function AppCard({ const isPlatform = useIsPlatform(); return ( -
-
-
- {/* Don't know why but w-[42px] isn't working, started happening when I started using next/dynamic */} - - {app?.name} - -
-
- - {app?.name} - +
+ +
+ {app?.name} {!app?.isInstalled && ( {app?.categories[0].charAt(0).toUpperCase() + app?.categories[0].slice(1)} )}
-

- {description || app?.description} -

+ {app?.description}
-
- {app.credentialOwner && !isPlatform && ( + } + iconSlot={ + + {app?.name} + + }> +
+
+ {/* {app.credentialOwner && !isPlatform && (
@@ -101,10 +91,11 @@ export default function AppCard({
- )} + )} */} {app?.isInstalled || app.credentialOwner ? (
{ if (switchOnClick) { @@ -128,32 +119,31 @@ export default function AppCard({ )}
-
- {hideAppCardOptions ? null : ( -
- {app?.isInstalled && switchChecked &&
} - - {app?.isInstalled && switchChecked ? ( - app.isSetupAlready === undefined || app.isSetupAlready ? ( -
- {!hideSettingsIcon && !isPlatform && ( - -
+
+ )} +
+ )} + ); } diff --git a/packages/app-store/salesforce/components/EventTypeAppCardInterface.tsx b/packages/app-store/salesforce/components/EventTypeAppCardInterface.tsx index c280d52f5f..40af307495 100644 --- a/packages/app-store/salesforce/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/salesforce/components/EventTypeAppCardInterface.tsx @@ -10,9 +10,10 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import { SchedulingType } from "@calcom/prisma/enums"; import { Alert } from "@calcom/ui/components/alert"; import { Button } from "@calcom/ui/components/button"; -import { InputField } from "@calcom/ui/components/form"; +import { InputField, Label } from "@calcom/ui/components/form"; import { Select } from "@calcom/ui/components/form"; import { Switch } from "@calcom/ui/components/form"; +import { Section } from "@calcom/ui/components/section"; import { showToast } from "@calcom/ui/components/toast"; import { SalesforceRecordEnum } from "../lib/enums"; @@ -74,14 +75,21 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ // Used when creating events under leads or contacts under account const CreateContactUnderAccount = () => { return ( - { - setAppData("createNewContactUnderAccount", checked); - }} - /> + + + { + setAppData("createNewContactUnderAccount", checked); + }} + /> + + ); }; @@ -95,107 +103,135 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ }} switchChecked={enabled} hideSettingsIcon> - <> -
- - { + if (e) { + setCreateEventOnSelectedOption(e); + setAppData("createEventOn", e.value); + } + }} + /> + + + + + + { + setAppData("ignoreGuests", checked); + }} + /> + + + {createEventOnSelectedOption.value === SalesforceRecordEnum.CONTACT ? ( -
- { - setAppData("skipContactCreation", checked); - }} - /> -
+ + + { + setAppData("skipContactCreation", checked); + }} + /> + + ) : null} + {createEventOnSelectedOption.value === SalesforceRecordEnum.LEAD ? ( -
- { - setAppData("createEventOnLeadCheckForContact", checked); - }} - /> -
- -
-
+ <> + + + + + + + ) : null} {createEventOnSelectedOption.value === SalesforceRecordEnum.ACCOUNT ? ( <> -
- -
-
- { - setAppData("createLeadIfAccountNull", checked); - }} - /> -
+ + + + { + setAppData("createLeadIfAccountNull", checked); + }} + /> + + ) : null} -
- { - setAppData("onBookingWriteToEventObject", checked); - }} - /> + + + { + setAppData("onBookingWriteToEventObject", checked); + }} + /> + {onBookingWriteToEventObject ? ( -
-
-
{t("field_name")}
-
{t("value")}
+ +
+
{t("field_name")}
+
{t("value")}
+
-
+ {Object.keys(onBookingWriteToEventObjectMap).map((key) => ( -
-
- +
+
+
-
- +
+
-
+
))} -
-
+
+
setNewOnBookingWriteToEventObjectField({ @@ -217,8 +255,10 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ } />
-
+
setNewOnBookingWriteToEventObjectField({ @@ -228,11 +268,13 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ } />
+
-
+ -
+ ) : null} -
+ -
+ setAppData("onBookingWriteToRecordFields", data)} /> -
+ -
- { - setAppData("onBookingChangeRecordOwner", checked); - }} - /> -
- {onBookingChangeRecordOwner ? ( -
-

{t("salesforce_owner_name_to_change")}

- setAppData("onBookingChangeRecordOwnerName", e.target.value)} - /> -
- ) : null} - - {eventType.schedulingType === SchedulingType.ROUND_ROBIN ? ( -
+ + { - setAppData("roundRobinLeadSkip", checked); - if (checked) { - // temporary solution, enabled should always be already set - setAppData("enabled", checked); - } + setAppData("onBookingChangeRecordOwner", checked); }} /> - {isRoundRobinLeadSkipEnabled ? ( - <> -
- - { + if (e) { + setCheckOwnerSelectedOption(e); + setAppData("roundRobinSkipCheckRecordOn", e.value); + } }} />
- ) : null} -
- { - setAppData("ifFreeEmailDomainSkipOwnerCheck", checked); - }} - /> -
- - ) : null} - -
+ + ) : null} + + <> + {isRoundRobinLeadSkipEnabled ? ( + <> + {checkOwnerSelectedOption.value === SalesforceRecordEnum.CONTACT ? ( + + + { + setAppData("roundRobinSkipFallbackToLeadOwner", checked); + }} + /> + + + ) : null} + + + { + setAppData("ifFreeEmailDomainSkipOwnerCheck", checked); + }} + /> + + + + + ) : null} + + ) : null} -
+ setAppData("onCancelWriteToEventRecordFields", data)} /> -
+ -
- { - setAppData("sendNoShowAttendeeData", checked); - }} - /> + + + { + setAppData("sendNoShowAttendeeData", checked); + }} + /> + {sendNoShowAttendeeData ? ( -
-

Field name to check (must be checkbox data type)

+ + setAppData("sendNoShowAttendeeDataField", e.target.value)} /> -
+ ) : null} -
- + + ); }; diff --git a/packages/app-store/salesforce/components/components/WriteToObjectSettings.tsx b/packages/app-store/salesforce/components/components/WriteToObjectSettings.tsx index d0b9decc5c..742610a117 100644 --- a/packages/app-store/salesforce/components/components/WriteToObjectSettings.tsx +++ b/packages/app-store/salesforce/components/components/WriteToObjectSettings.tsx @@ -6,6 +6,7 @@ import { Button } from "@calcom/ui/components/button"; import { Switch } from "@calcom/ui/components/form"; import { InputField } from "@calcom/ui/components/form"; import { Select } from "@calcom/ui/components/form"; +import { Section } from "@calcom/ui/components/section"; import { showToast } from "@calcom/ui/components/toast"; import { WhenToWriteToRecord, SalesforceFieldType, DateFieldTypeData } from "../../lib/enums"; @@ -81,37 +82,45 @@ const WriteToObjectSettings = ({ return ( <> - + + + + {optionEnabled ? ( -
-
-
{t("field_name")}
-
{t("field_type")}
-
{t("value")}
-
{t("when_to_write")}
+ +
+
{t("field_name")}
+
{t("field_type")}
+
{t("value")}
+
{t("when_to_write")}
+
-
+ {Object.keys(writeToObjectData).map((key) => ( -
-
- +
+
+
-
+
option.value === writeToObjectData[key].value )} @@ -119,28 +128,38 @@ const WriteToObjectSettings = ({ /> ) : writeToObjectData[key].fieldType === SalesforceFieldType.CHECKBOX ? ( option.value === writeToObjectData[key].whenToWrite )} isDisabled={true} />
-
+
))} -
-
+
+
setNewOnWriteToRecordEntry({ @@ -162,8 +183,10 @@ const WriteToObjectSettings = ({ } />
-
+
{ @@ -198,6 +223,8 @@ const WriteToObjectSettings = ({ /> ) : newOnWriteToRecordEntry.fieldType === SalesforceFieldType.CHECKBOX ? ( { @@ -237,10 +268,13 @@ const WriteToObjectSettings = ({ }} />
+
-
+ -
+ ) : null} ); diff --git a/packages/features/eventtypes/components/tabs/apps/EventAppsTab.tsx b/packages/features/eventtypes/components/tabs/apps/EventAppsTab.tsx index d5613630eb..492a20e9fa 100644 --- a/packages/features/eventtypes/components/tabs/apps/EventAppsTab.tsx +++ b/packages/features/eventtypes/components/tabs/apps/EventAppsTab.tsx @@ -13,6 +13,7 @@ import { trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/components/alert"; import { Button } from "@calcom/ui/components/button"; import { EmptyScreen } from "@calcom/ui/components/empty-screen"; +import { Section } from "@calcom/ui/components/section"; export type EventType = Pick["eventType"] & EventTypeAppCardComponentProps["eventType"]; @@ -91,7 +92,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => { return ( <>
-
+
{(isManagedEventType || isChildrenManagedEventType) && ( { })}
+ {/* TODO: Add back after salesforce v3 dev */} {!appsDisableProps.disabled && ( -
+
{!isPending && notInstalledApps?.length ? ( - <> -

- {t("available_apps_lower_case")} -

-

+

+ {t("available_apps_lower_case")} + { , ]} /> -

- +
+
) : null} -
+
{notInstalledApps?.map((app) => ( ({ ...base, - minHeight: size === "sm" ? "28px" : "36px", - height: grow ? "auto" : size === "sm" ? "28px" : "36px", + minHeight: size === "sm" ? "28px" : "32px", + height: grow ? "auto" : size === "sm" ? "28px" : "32px", }), }} classNames={{ @@ -67,7 +67,7 @@ export const Select = < innerClassNames?.option ), placeholder: (state) => cx("text-muted", state.isFocused && variant !== "checkbox" && "hidden"), - dropdownIndicator: () => "text-default", + dropdownIndicator: () => cx("text-default w-4 h-4"), control: (state) => cx( inputStyles({ size }), @@ -78,8 +78,8 @@ export const Select = < ? "p-1 h-fit" : "px-3 h-fit" : size === "sm" - ? "h-7 px-2" - : "h-9 px-3", + ? "h-7 px-2 py-1" + : "h-8 px-3 py-2", props.isDisabled && "bg-subtle", "rounded-[10px]", "[&:focus-within]:border-emphasis [&:focus-within]:shadow-outline-gray-focused [&:focus-within]:ring-0 !flex", @@ -108,11 +108,12 @@ export const Select = < cx( state.selectProps.menuIsOpen ? hasMultiLastIcons - ? "[&>*:last-child]:rotate-180 [&>*:last-child]:transition-transform" - : "rotate-180 transition-transform" - : "text-default" // Woo it adds another SVG here on multi for some reason + ? "[&>*:last-child]:rotate-180 [&>*:last-child]:transition-transform [&>*:last-child]:w-4 [&>*:last-child]:h-4" + : "rotate-180 transition-transform w-4 h-4" + : "text-default w-4 h-4" ), multiValueRemove: () => "text-default py-auto", + ...classNames, }} {...restProps} diff --git a/packages/ui/components/section/index.ts b/packages/ui/components/section/index.ts new file mode 100644 index 0000000000..d4898871d7 --- /dev/null +++ b/packages/ui/components/section/index.ts @@ -0,0 +1 @@ +export * from "./section"; diff --git a/packages/ui/components/section/section.tsx b/packages/ui/components/section/section.tsx new file mode 100644 index 0000000000..f6a6273b68 --- /dev/null +++ b/packages/ui/components/section/section.tsx @@ -0,0 +1,230 @@ +import { useAutoAnimate } from "@formkit/auto-animate/react"; +import { Slot } from "@radix-ui/react-slot"; + +import cn from "../../classNames"; +import type { IconName } from "../icon"; +import { Icon as IconComponent } from "../icon"; + +const Root = ({ + children, + ref, + className, +}: { + children: React.ReactNode; + ref?: React.Ref; + className?: string; +}) => { + const [animateRef] = useAutoAnimate(); + + return ( +
+ {children} +
+ ); +}; + +const Title = ({ + children, + ref, + as, +}: { + children: React.ReactNode; + ref?: React.Ref; + as?: React.ElementType; +}) => { + const Component = as ? Slot : "h2"; + return ( + + {children} + + ); +}; + +const Description = ({ + children, + ref, + as, +}: { + children: React.ReactNode; + ref?: React.Ref; + as?: React.ElementType; +}) => { + const Component = as ? Slot : "h3"; + return ( + + {children} + + ); +}; + +const Icon = ({ + ref, + name, + size = "md", + iconSlot, +}: { + ref?: React.Ref; + size?: "sm" | "md"; + name?: IconName; + iconSlot?: React.ReactNode; +} & ({ name: IconName; iconSlot?: never } | { name?: never; iconSlot: React.ReactNode })) => { + return ( +
+ {iconSlot ? ( + iconSlot + ) : ( + + )} +
+ ); +}; + +const Header = ({ + children, + ref, + icon, + title, + description, + iconSlot, + rawHeading, +}: { + children?: React.ReactNode; + ref?: React.Ref; + icon?: IconName; + iconSlot?: React.ReactNode; + title?: string; + description?: string; + rawHeading?: React.ReactNode; +}) => { + return ( +
+
+ {icon && !iconSlot && } + {iconSlot && } +
+ {title && {title}} + {description && {description}} + {rawHeading && rawHeading} +
+
+ {children} +
+ ); +}; + +const Content = ({ children, ref }: { children: React.ReactNode; ref?: React.Ref }) => { + return ( +
+ {children} +
+ ); +}; + +const SubSection = ({ children, ref }: { children: React.ReactNode; ref?: React.Ref }) => { + const [animateRef] = useAutoAnimate(); + + return ( +
+ {children} +
+ ); +}; + +const SubSectionHeader = ({ + children, + ref, + icon, + title, + classNames, + justify = "between", + labelFor, +}: { + children: React.ReactNode; + icon?: IconName; + title: string; + labelFor?: string; + classNames?: { + container?: string; + title?: string; + description?: string; + }; + ref?: React.Ref; + justify?: "between" | "start"; +}) => { + return ( +
+
+ {icon && } +
+

+ {title} +

+
+
+ {children} +
+ ); +}; + +const SubSectionContent = ({ + children, + ref, + invert, + classNames, +}: { + children: React.ReactNode; + ref?: React.Ref; + classNames?: { + container?: string; + }; + invert?: boolean; +}) => { + return ( +
+ {children} +
+ ); +}; + +const SubSectionNested = ({ + children, + ref, +}: { + children: React.ReactNode; + ref?: React.Ref; +}) => { + return ( +
+ {children} +
+ ); +}; + +export const Section = Object.assign(Root, { + Header: Header, + Content: Content, + Title: Title, + Description: Description, + SubSection: SubSection, + SubSectionHeader: SubSectionHeader, + SubSectionContent: SubSectionContent, + SubSectionNested: SubSectionNested, +}); diff --git a/packages/ui/package.json b/packages/ui/package.json index 922768882b..4769f98252 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -55,6 +55,7 @@ "./components/unpublished-entity": "./components/unpublished-entity/index.ts", "./components/table/TableNew": "./components/table/TableNew.tsx", "./components/app-list-card/AppListCard": "./components/app-list-card/AppListCard.tsx", + "./components/section": "./components/section/index.ts", "./__mocks__/ui": "./__mocks__/ui.tsx" }, "license": "MIT",