UNPKG

@heymantle/react

Version:

Mantle's React component library

1 lines 34 kB
{"version":3,"file":"index.mjs","sources":["../src/utils/constants.ts","../src/components/core/MantleProvider/MantleProvider.tsx","../src/utils/features.ts","../src/utils/money.ts","../src/utils/plans.ts","../src/utils/views.ts"],"sourcesContent":["export const PlanAvailability = {\n Public: \"public\",\n CustomerTag: \"customerTag\",\n ShopifyPlan: \"shopifyPlan\",\n Customer: \"customer\",\n Hidden: \"hidden\",\n} as const;\n\nexport const Labels = {\n AmountPerInterval: \"{{ amount }} per {{ interval }}\",\n Back: \"Back\",\n Cancel: \"Cancel\",\n CancelConfirmation: \"Are you sure you want to cancel your subscription?\",\n CancelPlan: \"Cancel plan\",\n ChangePlan: \"Change plan\",\n CurrentPlan: \"Current plan\",\n CustomPlans: \"Custom plans\",\n CustomPlansDescription: \"Plans tailored to your specific needs\",\n DiscountAmount: \"{{ amount }} discount\",\n DiscountAmountExpired: \"{{ amount }} discount expired\",\n FreeTrialLength: \"{{ trialDays }}-day free trial\",\n Features: \"Features\",\n Month: \"month\",\n MonthShort: \"mo\",\n Monthly: \"Monthly\",\n NextBillingDate: \"Next billing date\",\n NotSubscribed: \"You're not subscribed to a plan yet.\",\n Year: \"year\",\n YearShort: \"yr\",\n Yearly: \"Yearly\",\n MostPopular: \"Most popular\",\n Per: \"/\",\n Plans: \"Plans\",\n Price: \"Price\",\n SelectPlan: \"Select plan\",\n SubscribeSuccessTitle: \"Subscription successful\",\n SubscribeSuccessBody: \"Thanks for subscribing to our app!\",\n Subscription: \"Subscription\",\n SubscriptionCancelled: \"Subscription cancelled\",\n UsageCharges: \"Usage charges\",\n\n // Common\n loading: \"Loading...\",\n error: \"An error occurred\",\n retry: \"Retry\",\n cancel: \"Cancel\",\n continue: \"Continue\",\n \n // Subscription\n subscribe: \"Subscribe\",\n subscribeNow: \"Subscribe Now\",\n upgradeNow: \"Upgrade Now\",\n manageSubscription: \"Manage Subscription\",\n cancelSubscription: \"Cancel Subscription\",\n \n // Payment\n addPaymentMethod: \"Add Payment Method\",\n updatePaymentMethod: \"Update Payment Method\",\n \n // Features\n featureNotAvailable: \"This feature is not available on your current plan\",\n upgradeRequired: \"Upgrade Required\",\n limitReached: \"Limit Reached\",\n} as const;\n","import type {\n Customer,\n Feature,\n HostedSession,\n MantleError,\n Notify,\n Plan,\n RequirePaymentMethodOptions,\n SetupIntent,\n Subscription,\n SuccessResponse,\n UsageEvent,\n UsageMetricReport,\n} from \"@heymantle/client\";\nimport { MantleClient } from \"@heymantle/client\";\nimport React, { createContext, useContext, useEffect, useState } from \"react\";\nimport { Labels } from \"../../../utils/constants\";\n\n/** The main context interface that encapsulates functionality exposed by MantleProvider */\nexport interface TMantleContext {\n /** The MantleClient instance */\n client: MantleClient;\n /** The current customer */\n customer: Customer | null;\n /** The current subscription */\n subscription: Subscription | null;\n /** The available plans */\n plans: Plan[];\n /** Whether the current customer is loading */\n loading: boolean;\n /** Internationalization labels */\n i18n: typeof Labels;\n /** Refetch the current customer */\n refetch: () => Promise<void>;\n /** Send a new usage event to Mantle */\n sendUsageEvent: SendUsageEventCallback;\n /** Get a usage report for a usage metric */\n getUsageReport: GetUsageReportCallback;\n /** Subscribe to a new plan */\n subscribe: SubscribeCallback;\n /** Cancel the current subscription */\n cancelSubscription: CancelSubscriptionCallback;\n /** Start the process of adding a new payment method */\n addPaymentMethod: AddPaymentMethodCallback;\n /** Check if a feature is enabled */\n isFeatureEnabled: FeatureEnabledCallback;\n /** Get the limit for a feature */\n limitForFeature: FeatureLimitCallback;\n /** Create a hosted session */\n createHostedSession: HostedSessionCallback;\n /** Get a notifications */\n listNotifications: ListNotificationsCallback;\n /** Trigger a notification CTA */\n triggerNotificationCta: TriggerNotificationCtaCallback;\n /** Update a notification */\n updateNotification: UpdateNotificationCallback;\n /** Get the checklist */\n getChecklist: GetChecklistCallback;\n /** Complete a checklist step */\n completeChecklistStep: CompleteChecklistStepCallback;\n}\n\n/** Callback to send a new usage event to Mantle */\nexport type SendUsageEventCallback = (usageEvent: UsageEvent) => Promise<SuccessResponse>;\n\n/** Callback to get a usage report for a usage metric */\nexport type GetUsageReportCallback = (params: {\n /** The ID of the usage metric to get a report for */\n usageId: string;\n /** The period to get the usage report for */\n period: string;\n}) => Promise<{ report: UsageMetricReport } | MantleError>;\n\n/** Callback to get the checklist */\nexport type GetChecklistCallback = () => Promise<any>;\n\n/** Callback to complete a checklist step */\nexport type CompleteChecklistStepCallback = (params: {\n /** The ID of the checklist */\n checklistId: string;\n /** The ID of the checklist step to complete */\n checklistStepId: string;\n}) => Promise<any>;\n\n/** Common subscription parameters without the plan selection */\nexport type BaseSubscribeParams = {\n /** The ID of the discount to apply */\n discountId?: string;\n /** The billing provider to use */\n billingProvider?: string;\n /** The URL to return to after subscribing */\n returnUrl?: string;\n /** Whether to use the saved payment method for the customer. Defaults to true. */\n useSavedPaymentMethod?: boolean;\n /** The number of trial days to offer */\n trialDays?: number;\n /** (Stripe only) Whether to use Stripe checkout for the subscription. Not applicable for Shopify subscriptions as they are always hosted */\n hosted?: boolean;\n /** (Stripe only) The collection method to use for the subscription */\n collectionMethod?: string;\n /** (Stripe only) The number of days until the subscription is due */\n daysUntilDue?: number;\n /** (Stripe only) The payment method types to use for the subscription */\n paymentMethodTypes?: string[];\n /** (Stripe only) When to require a payment method for the subscription */\n requirePaymentMethod?: RequirePaymentMethodOptions;\n /** (Stripe only) Whether to automatically calculate tax for the subscription. Defaults to false. */\n automaticTax?: boolean;\n /** (Stripe checkout only) Tell the Stripe Checkout Session to require a billing address */\n requireBillingAddress?: boolean;\n /** (Stripe checkout only) Prefill the Stripe customer's email address */\n email?: string;\n /** (Stripe checkout only) Key-value pairs of metadata to attach to the subscription */\n metadata?: Record<string, string>;\n};\n\n/** Parameters for subscribing to a single plan */\nexport type SinglePlanSubscribe = BaseSubscribeParams & {\n /** The ID of the plan to subscribe to */\n planId: string;\n /** Not allowed when using planId */\n planIds?: never;\n};\n\n/** Parameters for subscribing to multiple plans */\nexport type MultiPlanSubscribe = BaseSubscribeParams & {\n /** Not allowed when using planIds */\n planId?: never;\n /** The IDs of the plans to subscribe to */\n planIds: string[];\n};\n\n/** Callback to subscribe to a new plan or plans */\nexport type SubscribeCallback = (\n params: SinglePlanSubscribe | MultiPlanSubscribe\n) => Promise<Subscription | MantleError>;\n\n/** Callback to cancel the current subscription */\nexport type CancelSubscriptionCallback = (params?: {\n /** The reason for canceling the subscription */\n cancelReason?: string;\n}) => Promise<Subscription | MantleError>;\n\n/** Callback to start the process of adding a new payment method */\nexport type AddPaymentMethodCallback = (params: {\n /** The URL to return to after connecting a new PaymentMethod */\n returnUrl: string;\n}) => Promise<SetupIntent | MantleError>;\n\n/** Callback to check if a feature is enabled */\nexport type FeatureEnabledCallback = (params: {\n /** The key of the feature to evaluate */\n featureKey: string;\n /** The count to evaluate against the feature limit if there is one */\n count?: number;\n}) => boolean;\n\n/** Callback to get the limit for a feature */\nexport type FeatureLimitCallback = (params: {\n /** The key of the feature to evaluate */\n featureKey: string;\n}) => number;\n\n/** Callback to create a hosted session */\nexport type HostedSessionCallback = (params: {\n /** The type of hosted session to create */\n type: string;\n /** The configuration for the hosted session */\n config: Record<string, any>;\n}) => Promise<HostedSession | MantleError>;\n\n/** Callback to list notifications */\nexport type ListNotificationsCallback = (params?: { email?: string }) => Promise<\n | {\n notifies: Notify[];\n hasMore: boolean;\n }\n | MantleError\n>;\n\n/** Callback to trigger a notification CTA */\nexport type TriggerNotificationCtaCallback = (params: {\n id: string;\n}) => Promise<SuccessResponse | MantleError>;\n\n/** Callback to update a notification */\nexport type UpdateNotificationCallback = (params: {\n id: string;\n readAt?: Date;\n dismissedAt?: Date;\n}) => Promise<SuccessResponse | MantleError>;\n\n/** Props for the MantleProvider component */\nexport interface MantleProviderProps {\n /** The Mantle App ID provided by Mantle */\n appId: string;\n /** The Mantle Customer API Token returned by the identify endpoint */\n customerApiToken: string;\n /** The Mantle API URL to use */\n apiUrl?: string;\n /** The children to render */\n children: React.ReactNode;\n /** The i18n object to use for labels */\n i18n?: typeof Labels;\n /** Whether to wait for the customer to be fetched */\n waitForCustomer?: boolean;\n /** The component to render while waiting for the customer to be fetched */\n loadingComponent?: React.ReactNode;\n /** Whether to throw an error if an error occurs */\n throwOnError?: boolean;\n}\n\n/** React Context for providing Mantle functionality throughout the app */\nconst MantleContext = createContext<TMantleContext | undefined>(undefined);\n\n/**\n * Evaluates whether a feature is enabled based on its type and value\n * @param feature - The feature to evaluate\n * @param count - The count to evaluate against if the feature is a limit type\n * @returns Whether the feature is considered enabled\n */\nconst evaluateFeature = ({ feature, count = 0 }: { feature: Feature; count?: number }): boolean => {\n if (feature?.type === \"boolean\") {\n return feature.value;\n } else if (feature?.type === \"limit\") {\n return count < feature.value || feature.value === -1;\n }\n return false;\n};\n\n/**\n * MantleProvider uses the React Context API to provide a MantleClient instance and\n * the current customer to its children, which can be accessed using the useMantle hook.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <MantleProvider\n * appId=\"your-app-id\"\n * customerApiToken=\"customer-token\"\n * >\n * <YourApp />\n * </MantleProvider>\n * );\n * }\n * ```\n */\nexport const MantleProvider: React.FC<MantleProviderProps> = ({\n appId,\n customerApiToken,\n apiUrl = \"https://appapi.heymantle.com/v1\",\n children,\n i18n = Labels,\n waitForCustomer = false,\n loadingComponent = null,\n throwOnError = false,\n}) => {\n const mantleClient = new MantleClient({ appId, customerApiToken, apiUrl });\n\n const [customer, setCustomer] = useState<Customer | null>(null);\n const [loading, setLoading] = useState(true);\n\n /**\n * Fetches the current customer from Mantle's API\n * Updates the customer state and handles loading states\n */\n const fetchCustomer = async () => {\n try {\n setLoading(true);\n const result = await mantleClient.getCustomer();\n if (result && \"error\" in result) {\n throw new Error(result.error);\n }\n setCustomer(result as Customer);\n } catch (error) {\n if (throwOnError) {\n throw error;\n } else {\n console.error(\"[MantleProvider] Error fetching customer: \", error);\n }\n } finally {\n setLoading(false);\n }\n };\n\n /**\n * Sends a usage event to Mantle\n * @param usageEvent - The usage event to send\n */\n const sendUsageEvent: SendUsageEventCallback = async (usageEvent) => {\n const result = await mantleClient.sendUsageEvent(usageEvent);\n if (\"error\" in result) {\n if (throwOnError) {\n throw new Error(result.error);\n }\n return {\n success: false,\n };\n }\n return result;\n };\n\n /**\n * Gets a usage report for a specific metric and period\n * @param params.usageId - The ID of the usage metric\n * @param params.period - The period to get the report for\n * @returns The usage report data\n */\n const getUsageReport: GetUsageReportCallback = async ({ usageId, period }) => {\n const result = await mantleClient.getUsageMetricReport({ id: usageId, period });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Subscribes to one or more plans\n * @param params - Either SinglePlanSubscribe or MultiPlanSubscribe parameters\n * @returns The created subscription\n */\n const subscribe: SubscribeCallback = async (params) => {\n const result = await mantleClient.subscribe(params);\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result as Subscription;\n };\n\n /**\n * Cancels the current subscription\n * @param params.cancelReason - Optional reason for cancellation\n * @returns The cancelled subscription\n */\n const cancelSubscription: CancelSubscriptionCallback = async ({ cancelReason } = {}) => {\n const result = await mantleClient.cancelSubscription({\n ...(cancelReason && { cancelReason }),\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Initiates the process of adding a new payment method\n * @param params.returnUrl - The URL to return to after adding the payment method\n * @returns A SetupIntent for completing the payment method addition\n * @throws Error if returnUrl is not provided\n */\n const addPaymentMethod: AddPaymentMethodCallback = async ({ returnUrl }) => {\n if (!returnUrl) {\n throw new Error(\"returnUrl is required\");\n }\n const result = await mantleClient.addPaymentMethod({ returnUrl });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Creates a hosted session for various checkout flows\n * @param params.type - The type of hosted session to create\n * @param params.config - Configuration options for the hosted session\n * @returns The created hosted session\n * @throws Error if type is not provided\n */\n const createHostedSession: HostedSessionCallback = async ({ type, config }) => {\n if (!type) {\n throw new Error(\"type is required\");\n }\n const searchParams = new URL(document.location.toString()).searchParams;\n const locale = searchParams.get(\"locale\");\n const result = await mantleClient.createHostedSession({\n type,\n config: {\n ...(locale ? { locale } : {}),\n ...(config || {}),\n },\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n const listNotifications: ListNotificationsCallback = async (params) => {\n const result = await mantleClient.listNotifications(params);\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n const triggerNotificationCta: TriggerNotificationCtaCallback = async ({ id }) => {\n const result = await mantleClient.triggerNotificationCta({ id });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n const updateNotification: UpdateNotificationCallback = async ({ id, readAt, dismissedAt }) => {\n const result = await mantleClient.updateNotification({ id, readAt, dismissedAt });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Gets the checklist for the current customer\n * @returns The checklist data\n */\n const getChecklist: GetChecklistCallback = async () => {\n const result = await mantleClient.getChecklist();\n if (result && \"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Completes a specific checklist step\n * @param params.checklistId - The ID of the checklist\n * @param params.checklistStepId - The ID of the checklist step to complete\n * @returns The completion result\n */\n const completeChecklistStep: CompleteChecklistStepCallback = async ({\n checklistId,\n checklistStepId,\n }) => {\n const result = await mantleClient.completeChecklistStep({ checklistId, checklistStepId });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n // Fetch customer when the token changes\n useEffect(() => {\n if (customerApiToken) {\n fetchCustomer();\n }\n }, [customerApiToken]);\n\n const plans = customer?.plans || [];\n const subscription = customer?.subscription || null;\n\n if (waitForCustomer && loading) {\n return loadingComponent || null;\n }\n\n return (\n <MantleContext.Provider\n value={{\n client: mantleClient,\n customer,\n subscription,\n plans,\n loading,\n i18n: { ...Labels, ...i18n },\n sendUsageEvent,\n getUsageReport,\n subscribe,\n cancelSubscription,\n addPaymentMethod,\n createHostedSession,\n listNotifications,\n triggerNotificationCta,\n updateNotification,\n getChecklist,\n completeChecklistStep,\n isFeatureEnabled: ({ featureKey, count = 0 }) => {\n if (customer?.features[featureKey]) {\n return evaluateFeature({\n feature: customer.features[featureKey],\n count,\n });\n }\n return false;\n },\n limitForFeature: ({ featureKey }) => {\n if (customer?.features[featureKey] && customer.features[featureKey].type === \"limit\") {\n return customer.features[featureKey].value;\n }\n return -1;\n },\n refetch: async () => {\n await fetchCustomer();\n },\n }}\n >\n {children}\n </MantleContext.Provider>\n );\n};\n\n/**\n * React hook to access the Mantle context\n * Must be used within a MantleProvider component\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { customer, subscription } = useMantle();\n * return <div>Hello {customer?.name}</div>;\n * }\n * ```\n *\n * @returns The Mantle context containing all Mantle functionality\n * @throws Error if used outside of a MantleProvider\n */\nexport const useMantle = (): TMantleContext => {\n const context = useContext(MantleContext);\n\n if (context === undefined) {\n throw new Error(\"useMantle must be used within a MantleProvider\");\n }\n\n return context;\n};\n","import type { Feature } from '@heymantle/client';\n\n/**\n * Determines if a feature is enabled based on its type and value\n * @param feature - The feature to check\n * @returns true if the feature is enabled\n */\nexport const featureEnabled = (feature: Feature): boolean => {\n return (\n (feature.type === \"boolean\" && feature.value === true) ||\n (feature.type === \"limit\" && feature.value !== 0)\n );\n};\n\n/**\n * Sorts features by enabled status (enabled first) and then by name\n * @param a - First feature to compare\n * @param b - Second feature to compare\n * @returns Sort order (-1, 0, or 1)\n */\nexport const featureSort = (a: Feature, b: Feature): number =>\n (Number(featureEnabled(b)) - Number(featureEnabled(a))) || a.name.localeCompare(b.name); ","/**\n * Creates a number formatter for the specified currency\n * @param currencyCode - The currency code to format for\n * @returns An Intl.NumberFormat instance configured for the currency\n */\nconst moneyFormatter = (currencyCode: string = \"USD\"): Intl.NumberFormat =>\n new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: currencyCode,\n notation: \"standard\",\n });\n\n/**\n * Formats the given amount of money based on the specified currency code\n * @param amount - The amount of money to format\n * @param currencyCode - The currency code to use for formatting\n * @param removeCents - Whether to remove the cents from the formatted result\n * @returns The formatted money string\n * \n * @example\n * ```ts\n * money(1234.56) // \"$1,234.56\"\n * money(1234.56, \"USD\", true) // \"$1,234\"\n * money(1234.56, \"EUR\") // \"€1,234.56\"\n * ```\n */\nexport const money = (\n amount: number,\n currencyCode: string = \"USD\",\n removeCents: boolean = true\n): string => {\n let result = moneyFormatter(currencyCode).format(amount);\n if (removeCents) {\n result = result.replace(/\\.00$/, '');\n }\n return result;\n}; ","import type { Discount, Plan } from \"@heymantle/client\";\nimport { Labels } from \"./constants\";\n\nexport enum PlanInterval {\n Annual = \"ANNUAL\",\n Every30Days = \"EVERY_30_DAYS\",\n}\n\ntype IntervalLabelType = \"year\" | \"month\";\ntype IntervalLabelShortType = \"yr\" | \"mo\";\n\n/**\n * Generate a long label for the given interval\n * @param interval - The interval to generate a label for\n * @returns The long label for the interval\n */\nexport const intervalLabelLong = (interval: PlanInterval = PlanInterval.Every30Days): IntervalLabelType => {\n switch (interval) {\n case PlanInterval.Annual:\n return \"year\";\n case PlanInterval.Every30Days:\n default:\n return \"month\";\n }\n};\n\n/**\n * Generate a short label for the given interval\n * @param interval - The interval to generate a label for\n * @returns The short label for the interval\n */\nexport const intervalLabelShort = (interval: PlanInterval = PlanInterval.Every30Days): IntervalLabelShortType => {\n switch (interval) {\n case PlanInterval.Annual:\n return \"yr\";\n case PlanInterval.Every30Days:\n default:\n return \"mo\";\n }\n};\n\ninterface IntervalLabelParams {\n interval?: PlanInterval;\n useShortFormPlanIntervals?: boolean;\n}\n\n/**\n * Generate a label for the given interval and format\n * @param params.interval - The interval to generate a label for\n * @param params.useShortFormPlanIntervals - Whether to use short form plan intervals\n * @returns The label for the interval\n */\nexport const intervalLabel = ({\n interval = PlanInterval.Every30Days,\n useShortFormPlanIntervals = true,\n}: IntervalLabelParams): IntervalLabelType | IntervalLabelShortType => {\n return useShortFormPlanIntervals ? intervalLabelShort(interval) : intervalLabelLong(interval);\n};\n\ninterface PlanParams {\n plan: Plan;\n customFieldKey?: string;\n}\n\n/**\n * Check if the plan is recommended by using custom fields\n * @param params.plan - The Mantle plan to check\n * @param params.customFieldKey - The key to check for the recommended status\n * @returns Whether the plan is recommended\n */\nexport const isRecommendedPlan = ({ \n plan, \n customFieldKey = \"recommended\" \n}: PlanParams): boolean => {\n return !!plan.customFields?.[customFieldKey];\n};\n\n/**\n * Get the custom button label for the plan, or the default label\n * @param params.plan - The Mantle plan to check\n * @param params.customFieldKey - The key to check for the button label\n * @returns The custom button label or the default label\n */\nexport const customButtonLabel = ({ \n plan, \n customFieldKey = \"buttonLabel\" \n}: PlanParams): string => {\n return plan.customFields?.[customFieldKey] || Labels.subscribe;\n};\n\n/**\n * Get the best discount for the plan\n * @param params.plan - The Mantle plan to check for a discount\n * @returns The highest discount for the plan, or undefined if none found\n */\nexport const highestDiscount = ({ plan }: { plan: Plan }): Discount | undefined => {\n return plan.discounts?.length > 0\n ? plan.discounts.reduce((prev, current) =>\n prev.discountedAmount < current.discountedAmount ? prev : current\n )\n : undefined;\n}; ","interface ColumnSpans {\n xs: number;\n sm: number;\n md: number;\n lg: number;\n xl: number;\n}\n\n/**\n * Get the column span for the grid layout\n * @param count - The number of columns\n * @returns The column span for each screen size\n * \n * @example\n * ```ts\n * columnSpan(4) // { xs: 6, sm: 6, md: 2, lg: 3, xl: 3 }\n * columnSpan(3) // { xs: 6, sm: 6, md: 2, lg: 4, xl: 4 }\n * ```\n */\nexport const columnSpan = (count: number = 4): ColumnSpans => {\n if (count % 4 === 0) return { xs: 6, sm: 6, md: 2, lg: 3, xl: 3 };\n if (count % 3 === 0) return { xs: 6, sm: 6, md: 2, lg: 4, xl: 4 };\n if (count % 2 === 0) return { xs: 6, sm: 6, md: 3, lg: 6, xl: 6 };\n if (count === 1) return { xs: 6, sm: 6, md: 6, lg: 12, xl: 12 };\n return { xs: 6, sm: 6, md: 2, lg: 4, xl: 4 };\n};\n\n/**\n * Get the column count for the grid layout\n * @param size - The number of items\n * @returns The number of columns\n * \n * @example\n * ```ts\n * columnCount(4) // 4\n * columnCount(3) // 3\n * columnCount(2) // 2\n * ```\n */\nexport const columnCount = (size: number = 4): number => {\n if (size % 4 === 0) return 4;\n if (size % 3 === 0) return 3;\n if (size % 2 === 0) return 2;\n if (size === 1) return 1;\n return 4;\n}; "],"names":["PlanAvailability","Labels","MantleContext","createContext","evaluateFeature","feature","count","MantleProvider","appId","customerApiToken","apiUrl","children","i18n","waitForCustomer","loadingComponent","throwOnError","mantleClient","MantleClient","customer","setCustomer","useState","loading","setLoading","fetchCustomer","result","error","sendUsageEvent","usageEvent","getUsageReport","usageId","period","subscribe","params","cancelSubscription","cancelReason","addPaymentMethod","returnUrl","createHostedSession","type","config","locale","listNotifications","triggerNotificationCta","id","updateNotification","readAt","dismissedAt","getChecklist","completeChecklistStep","checklistId","checklistStepId","useEffect","plans","subscription","jsx","featureKey","useMantle","context","useContext","featureEnabled","featureSort","a","b","moneyFormatter","currencyCode","money","amount","removeCents","PlanInterval","intervalLabelLong","interval","intervalLabelShort","intervalLabel","useShortFormPlanIntervals","isRecommendedPlan","plan","customFieldKey","_a","customButtonLabel","highestDiscount","prev","current","columnSpan","columnCount","size"],"mappings":"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"}