UNPKG

burnout-components

Version:

A component library for burnout brands that contains common react-components and util functions used throughout it and it's portfolio companies

825 lines (626 loc) 19.9 kB
# Burnout Components ## Table of Contents - [Features](#features) - [Installing](#installing) - [Styling](#styling) - [Client Components](#client-components) - [BurnoutButton](#burnoutbutton) - [MonsterButton](#monsterbutton) - [Client Form Components](#client-form-components) - [Server Functions/Components](#server-functions) - [Info](#info) - [BurnoutBreadCrumbNext](#burnoutbreadcrumbnext) - [BurnoutButtonLinkNext](#burnoutbuttonlinknext) - [BurnoutInfoCard](#burnoutinfocard) - [BurnoutStyledLinkNext](#burnoutstyledlinknext) - [GlassMonsterBreadCrumbNext](#glassmonsterbreadcrumbnext) - [GlassMonsterInfoCard](#glassmonsterinfocard) - [MonsterBreadCrumbNext](#monsterbreadcrumbnext) - [MonsterButtonLinkNext](#monsterbuttonlinknext) - [MonsterGlassButtonLinkNext](#monsterglassbuttonlinknext) - [MonsterInfoCard](#monsterinfocard) - [MonsterStyledLinkNext](#monsterstyledlinknext) - [TailwindLoadingSpinner](#tailwindloadingspinner) - [Utility Functions](#utility-functions) - [capitalizeFirstLetters](#capitalizefirstletters) - [createDollarAmount](#createdollaramount) - [createQueryStringNext](#createquerystringnext) - [extractNumber](#extractnumber) - [formatPhone](#formatphone) - [trimStringProperties](#trimstringproperties) - [truncateText](#truncatetext) - [tryCatch](#trycatch) ## Features - Styled Client/Server Components for Next.js/React (can be used with any React app) - Styled Client Form Components for use with Zod and TanStack Form - Utility functions that can run on either client or server - Intended for standardized styling and form validation across Burnout Brand companies for both internal and external use - Reduces boilerplate in Burnout Brands projects ## Installing Using npm: ```bash npm install burnout-components ``` Using yarn: ```bash yarn add burnout-components ``` Using bun: ```bash bun install burnout-components ``` Using pnpm: ```bash pnpm add burnout-components ``` Using bower: ```bash bower install burnout-components ``` Once the package is installed, you can import the library using `import` approach: ```typescript import { MonsterButton } from 'burnout-components'; import { tryCatch } from 'burnout-components/server'; ``` ## Styling You must have Tailwind CSS installed and configured in your project. You must then import `burnout-components/styles.css` in either your root layout or your App file. ## Client Components These must be used with the 'use client' directive at the top of the file if you are using react 18 (I think) and above. ### BurnoutButton Props and their types: - children: React.ReactNode - colorSwap: boolean (optional, default false) - disabled: boolean (optional, default false) - fit: boolean (optional, default false, false = full width, true = fit to content) - onClick: () => void (optional) - red: boolean (optional, default false) - type: 'button' | 'submit' (optional, default submit) ```tsx import { BurnoutButton } from 'burnout-compoents'; function SomeButton() {} return ( <BurnoutButton type='button' fit red onClick={() => console.log('Clicked!')}> Click Me! </BurnoutButton> ) } ``` ### MonsterButton Props and their types: - children: React.ReactNode - colorSwap: boolean (optional, default false) - disabled: boolean (optional, default false) - fit: boolean (optional, default false, false = full width, true = fit to content) - onClick: () => void (optional) - red: boolean (optional, default false) - type: 'button' | 'submit' (optional, default submit) ```tsx import { MonsterButton } from 'burnout-compoents'; function SomeButton() {} return ( <MonsterButton type='button' fit red onClick={() => console.log('Clicked!')}> Click Me! </MonsterButton> ) } ``` ## Client Form Components These are styled components that are meant to be used with Zod and TanStack Form. They all need to be wrapped with `FormWrapper` and must before the end of `FormWrapper` must contain a submit button like this: ```tsx <form.AppForm> <form.MonsterSubmitButton text='Update Role' submittingText='Updating...' /> </form.AppForm> ``` All available components are: - FormWrapper - BurnoutCheckbox - BurnoutMultiSelect - BurnoutRichTextEditor - BurnoutSelectField - BurnoutSubmitButton - BurnoutTextAreaField - BurnoutTextField - GlassCheckbox - GlassRichTextEditor - GlassSelectField - GlassTextAreaField - GlassTextField - MonsterCheckbox - MonsterMultiSelect - MonsterRichTextEditor - MonsterSelectField - MonsterSubmitButton - MonsterGlassSubmitButton - MonsterTextAreaField - MonsterTextField ### MonsterGlassSubmitButton Props and their types: - colorSwap: boolean (optional, default false) - text: string (optional, default 'Submit') - submittingText: string (optional, default 'Submitting...') The MonsterGlassSubmitButton uses the TanStack Form context to determine if the form can be submitted. If there are validation errors, clicking the button will display an alert with all error messages. The button automatically disables when the form is submitting or when validation fails. #### MonsterGlassSubmitButton Example ```tsx import { FormWrapper, useAppForm } from 'burnout-components'; import { z } from 'zod'; function Form() { const form = useAppForm({ defaultValues: { name: '', email: '' }, onSubmit: async ({ value }) => { // Submit form data }, validators: { onChange: { name: z.string().min(1, 'Name is required'), email: z.string().email('Invalid email address') } } }); return ( <FormWrapper handleSubmit={form.handleSubmit}> <form.AppField name='name'> {(field) => ( <field.GlassTextField label='Name' /> )} </form.AppField> <form.AppField name='email'> {(field) => ( <field.GlassTextField label='Email' type='email' /> )} </form.AppField> <form.AppForm> <form.MonsterGlassSubmitButton colorSwap text='Create Account' submittingText='Creating...' /> </form.AppForm> </FormWrapper> ); } ``` ### Form Example ```tsx import { FormWrapper } from 'burnout-compoents'; import { useAppForm } from 'burnout-compoents/'; import { z } from 'zod'; // You can also import like this but I prefer the former import { FormWrapper, useAppForm } from 'burnout-compoents'; function Form() { const form = useAppForm({ defaultValues: { name: '', email: '', manager: false, role: 'user', favoriteColors: [''], descriptionLong: '', descriptionShort: '' }, onSubmit: async ({ value }) => { const { name, email, manager, role, favoriteColors, descriptionLong, descriptionShort } = value; // Do something with the form values // This function does not have to be async }, validators: { onChange: { // You would normally define this somewhere else and import it in // Field Errors are built in and can be checked either on change or on submit, I like on change name: z.string().min(1, 'Name is required'), email: z.string().email('Invalid email address'), manager: z.boolean(), role: z.enum(['user', 'admin'], 'Role is required'), favoriteColors: z .array(z.string()) .min(1, 'At least one color is required'), descriptionLong: z.string().max(500, 'Description is too long'), descriptionShort: z.string().max(100, 'Description is too long') } } }); const colorOptions = ['red', 'green', 'blue']; return ( <FormWrapper handleSubmit={form.handleSubmit}> {/* Required is optional by default it is true on all relevant fields except checkboxes */} {/* Type is optional by default it is text on all relevant fields */} <form.AppField name='name'> {(field) => ( <field.MonsterTextField label='Name' autoFocus type='text' /> )} </form.AppField> <form.AppField name='email'> {(field) => ( <field.MonsterTextField label='Email' required={false} type='email' /> )} </form.AppField> <form.AppField name='manager'> {(field) => <field.MonsterCheckbox label='Is Manager' />} </form.AppField> <form.AppField name='role'> {(field) => ( <field.MonsterSelectField label='Role'> <option value='user'>User</option> <option value='admin'>Admin</option> </field.MonsterSelectField> )} </form.AppField> <form.AppField name='favoriteColors'> {(field) => ( <field.MonsterMultiSelect label='Favorite Colors' options={colorOptions} /> )} </form.AppField> <form.AppField name='descriptionLong'> {(field) => <field.MonsterRichTextEditor label='Long Description' />} </form.AppField> <form.AppField name='descriptionShort'> {(field) => <field.MonsterTextAreaField label='Short Description' />} </form.AppField> <form.AppForm> {/* default text is 'Submit' and default submitting text is 'Submitting...' */} <form.MonsterSubmitButton text='Create Person' submittingText='Creating...' /> </form.AppForm> </FormWrapper> ); } ``` ## Server Functions/Components ### Info Props and their types: - children: React.ReactNode - label: string #### Info Example ```tsx import { Info } from 'burnout-compoents/server' return TellingYouSomething() { return ( <Info label='Something Important'> <p>This is some important information</p> </Info> ) } ``` ### BurnoutBreadCrumbNext **_This is only for use in Next.js projects_** Props and their types: - colorSwap: boolean(optional, default false) - fromLabel: string; - href: string - linkLabel: string #### BurnoutBreadCrumbNext Example ```tsx import { BurnoutBreadCrumbNext } from 'burnout-compoents/server' return LinkingYouToSomething() { return ( <BurnoutBreadCrumbNext fromLabel='I am here' href='/somewhere' linkLabel='Somewhere' /> ) } ``` ### BurnoutButtonLinkNext **_This is only for use in Next.js projects_** Props and their types: - children: React.ReactNode - colorSwap: boolean (optional, default false) - href: string - prefetch: boolean (optional, default true) - target: '\_blank' | '\_self' | '\_parent' | '\_top' (optional, default \_self) #### BurnoutButtonLinkNext Example ```tsx import { BurnoutButtonLinkNext } from 'burnout-compoents/server' return LinkingYouToSomething() { return ( <BurnoutButtonLinkNext prefetch={false} href='/somewhere' target='_blank'> This goes somewhere </BurnoutButtonLinkNext> ) } ``` ### BurnoutInfoCard Props and their types: - children: React.ReactNode - colorSwap: boolean (optional, default false) - header: string #### BurnoutInfoCard Example ```tsx import { BurnoutInfoCard } from 'burnout-compoents/server' return SomeCard() { return ( <BurnoutInfoCard header='Some Header'> <div className='w-full flex flex-col gap-3'> <BurnoutInfoCard colorSwap header='Some Nested Header'> <p>This is some nested information</p> </MonsterInfoCard> </div> </MonsterButtonLinkNext> ) } ``` ### BurnoutStyledLinkNext **_This is only for use in Next.js projects_** Props and their types: - children: React.ReactNode - href: string - prefetch: boolean (optional, default true) - target: '\_blank' | '\_self' | '\_parent' | '\_top' (optional, default \_self) #### BurnoutStyledLinkNext Example ```tsx import { BurnoutStyledLinkNext } from 'burnout-compoents/server' return LinkingYouToSomething() { return ( <BurnoutStyledLinkNext prefetch={false} href='/somewhere' target='_blank'> This goes somewhere </BurnoutStyledLinkNext> ) } ``` ### MonsterBreadCrumbNext **_This is only for use in Next.js projects_** Props and their types: - colorSwap: boolean (optional, default false); - fromLabel: string; - href: string - linkLabel: string #### MonsterBreadCrumbNext Example ```tsx import { MonsterBreadCrumbNext } from 'burnout-compoents/server' return LinkingYouToSomething() { return ( <MonsterBreadCrumbNext fromLabel='I am here' href='/somewhere' linkLabel='Somewhere' /> ) } ``` ### MonsterButtonLinkNext **_This is only for use in Next.js projects_** Props and their types: - children: React.ReactNode - colorSwap: boolean (optional, default false) - href: string - prefetch: boolean (optional, default true) - target: '\_blank' | '\_self' | '\_parent' | '\_top' (optional, default \_self) #### MonsterButtonLinkNext Example ```tsx import { MonsterButtonLinkNext } from 'burnout-compoents/server' return LinkingYouToSomething() { return ( <MonsterButtonLinkNext prefetch={false} href='/somewhere' target='_blank'> This goes somewhere </MonsterButtonLinkNext> ) } ``` ### MonsterGlassButtonLinkNext **_This is only for use in Next.js projects_** Props and their types: - children: React.ReactNode - colorSwap: boolean (optional, default false) - href: string - prefetch: boolean (optional, default true) - target: '\_blank' | '\_self' | '\_parent' | '\_top' (optional, default \_self) #### MonsterGlassButtonLinkNext Example ```tsx import { MonsterGlassButtonLinkNext } from 'burnout-compoents/server' return LinkingYouToSomething() { return ( <MonsterGlassButtonLinkNext prefetch={false} href='/somewhere' target='_blank'> This goes somewhere </MonsterGlassButtonLinkNext> ) } ``` ### MonsterInfoCard Props and their types: - children: React.ReactNode - colorSwap: boolean (optional, default false) - header: string #### MonsterInfoCard Example ```tsx import { MonsterInfoCard } from 'burnout-compoents/server' return SomeCard() { return ( <MonsterInfoCard header='Some Header'> <div className='w-full flex flex-col gap-3'> <MonsterInfoCard colorSwap header='Some Nested Header'> <p>This is some nested information</p> </MonsterInfoCard> </div> </MonsterButtonLinkNext> ) } ``` ### MonsterStyledLinkNext **_This is only for use in Next.js projects_** Props and their types: - children: React.ReactNode - href: string - prefetch: boolean (optional, default true) - target: '\_blank' | '\_self' | '\_parent' | '\_top' (optional, default \_self) #### MonsterStyledLinkNext Example ```tsx import { MonsterStyledLinkNext } from 'burnout-compoents/server' return LinkingYouToSomething() { return ( <MonsterStyledLinkNext prefetch={false} href='/somewhere' target='_blank'> This goes somewhere </MonsterStyledLinkNext> ) } ``` ### GlassMonsterBreadCrumbNext **_This is only for use in Next.js projects_** Props and their types: - colorSwap: boolean (optional, default false) - fromLabel: string - href: string - linkLabel: string The GlassMonsterBreadCrumbNext component provides a glass-style breadcrumb navigation element using the MonsterGlassButtonLinkNext component internally. It displays a link button followed by a chevron icon and the current page label. #### GlassMonsterBreadCrumbNext Example ```tsx import { GlassMonsterBreadCrumbNext } from 'burnout-compoents/server' return BreadcrumbNavigation() { return ( <GlassMonsterBreadCrumbNext colorSwap fromLabel="Current Page" href="/previous-page" linkLabel="Previous Page" /> ) } ``` ### GlassMonsterInfoCard Props and their types: - children: React.ReactNode - colorSwap: boolean (optional, default false) - header: number | string The GlassMonsterInfoCard component provides a glass-style card with a header and content area. It features a backdrop blur effect and subtle transparency for a modern UI appearance. #### GlassMonsterInfoCard Example ```tsx import { GlassMonsterInfoCard } from 'burnout-compoents/server' return InformationDisplay() { return ( <GlassMonsterInfoCard header="Important Information"> <div className="space-y-4"> <p>This is some important information displayed in a glass-style card.</p> <GlassMonsterInfoCard colorSwap header="Additional Details"> <p>You can nest these cards for hierarchical information display.</p> </GlassMonsterInfoCard> </div> </GlassMonsterInfoCard> ) } ``` ### TailwindLoadingSpinner This is small and meant for inline loading spinners. It is not a full page loading. Props and their types: - fill: 'blue' | 'green' | 'red' | 'yellow' (optional, default blue) #### TailwindLoadingSpinner Example ```tsx import { TailwindLoadingSpinner } from 'burnout-compoents/server' return SomeBadLoading() { return ( <TailwindLoadingSpinner fill='red' /> ) } ``` ## Utility Functions ### capitalizeFirstLetters #### capitalizeFirstLetters Example ```typescript import { capitalizeFirstLetters } from 'burnout-components/server'; const text = 'hello world'; const newText = capitalizeFirstLetters(text); console.log(newText); // Output: Hello World ``` ### createDollarAmount #### createDollarAmount Example ```typescript import { createDollarAmount } from 'burnout-components/server'; const amountString = '200'; const newAmountOne = createDollarAmount(amountString); console.log(newAmountOne); // Output: $200.00 const amountNumber = 200; const newAmountTwo = createDollarAmount(amountNumber); console.log(newAmountTwo); // Output: $200.00 ``` ### createQueryStringNext This is only for use in Next.js projects. #### createQueryStringNext Example ```typescript import { createQueryStringNext } from 'burnout-components/server'; import { usePathname, useRouter, useSearchParams } from 'next/naviagtion'; const pathname = usePathname(); const router = useRouter(); const searchParams = useSearchParams(); function handleSubmit(search: string) { router.push(`${pathname}?${createQueryString('search', search, searchParams}`) } ``` ### extractNumber #### extractNumber Example ```typescript import { extractNumber } from 'burnout-components/server'; const inputString = '2,812.30 refund minus 25% CANCELLATION FEE.'; const result = extractNumber(inputString); console.log(result); // Output: 2812.3 ``` ### formatPhone #### formatPhone Example ```typescript import { formatPhone } from 'burnout-components/server'; const phoneNumber = '1234567890'; const formattedPhone = formatPhone(phoneNumber); console.log(formattedPhone); // Output: (123) 456-7890 ``` ### trimStringProperties #### trimStringProperties Example ```typescript import { trimStringProperties } from 'burnout-components/server'; const userInput = { name: ' John Doe ', email: ' john@example.com ', age: 30, isActive: true, description: ' This is a description with extra spaces ' }; const trimmedData = trimStringProperties(userInput); console.log(trimmedData); // Output: { // name: 'John Doe', // email: 'john@example.com', // age: 30, // isActive: true, // description: 'This is a description with extra spaces' // } ``` ### truncateText #### truncateText Example ```typescript import { truncateText } from 'burnout-components/server'; const text 'Imagine this is super long text that needs to be truncated'; const truncatedText = truncateText(text, 20); console.log(truncatedText); // Output: Imagine this is super long... ``` ### tryCatch #### tryCatch Example ```typescript import { tryCatch } from 'burnout-components/server'; async function something() { const { data, error } = await tryCatch(async () => { const response = await fetch('/api/some-endpoint'); return response.json(); }); if (error) { console.error('Error fetching data:', error); } else { console.log('Fetched data:', data); } } ```