Utilities
Reusable functions for improved workflow
Some components in Webcore comes with JavaScript API that let’s you dynamically handle components. Apart from this functionality, Webcore also exposes a couple of other utility functions that you can use in your own codebase to speed up your development workflow. You’ll find the following utility function in Webcore.
webcoreui
. If you’d like to reuse some of the functionalities defined here in your own project without Webcore, you can find the implementations here. ClassNames
Use the classNames
function to dynamically and conditionally generate valid CSS class names. The function expects an array of elements. You can create conditions inside the array using logical operators. The array elements will be concatenated into a single class name.
import { classNames } from 'webcoreui'
classNames(['avatar', true && 'borderless']) -> 'avatar borderless'classNames(['avatar', false && 'borderless', null]) -> 'avatar'
const classNames: (classes: any[]) => string
Cookies
To work with cookies, use the getCookie
, setCookie
, and removeCookie
functions.
-
Getting cookies
import { getCookie } from 'webcoreui'getCookie('w-theme')Expects the name of the cookie as a string, and returns the value of the cookie if present. Returns
null
if no cookie is found. -
Setting cookies
import { setCookie } from 'webcoreui'setCookie('w-theme', 'theme-dark', 30)Sets the cookie for a specified duration. Expects, the name of the cookie as a string, the value of the cookie as a string, and the number of days in numbers. In the above example, the
w-theme
cookie will be set for 30 days before expiration with the value oftheme-dark
. -
Removing cookies
import { removeCookie } from 'webcoreui'removeCookie('w-theme')Removes the specified cookied. Pass the name of the cookie as a string you’d like to remove. No value is returned from the function.
const setCookie: (name: string, value: string, days: number) => voidconst getCookie: (name: string) => string | nullconst removeCookie: (name: string) => void
Debounce
Use the debounce
function to limit the rate at which a function is executed. Use for performance optimization for excessively executed functions, such as keyup, resize, or scroll events:
import { debounce } from 'webcoreui'
const callbackWithDebounce = debounce(() => { console.log('called with debounce')})
new ResizeObserver(() => { callbackWithDebounce()}).observe(document.body)
// Call `.cancel` to cancel a debounce earliercallbackWithDebounce.cancel()
Pass the callback function to the debounce
call that should be rate limited. Optionally, you can set a second parameter to configure the timeout for the debounce. By default, this is set to 100 milliseconds.
const debounce: <T extends (...args: any[]) => any>( fn: T, waitFor?: number) => { (...args: Parameters<T>): void cancel: () => void}
DOM Utilities
Webcore provides the following DOM utility functions to make the work with DOM elements easier in Astro components:
-
Getting DOM elements
import { get } from 'webcoreui'const element = get('.selector') // Get a single DOM elementconst element = get('.selectors', true) // Get all DOM elements with the selectorUse the
get
utility function to select DOM elements. Passtrue
as the second parameter to get all DOM elements with the specified selector. The selector can be a valid HTML query selector. -
Adding event listeners
import { on } from 'webcoreui'on('button', 'click', () => console.log('Button clicked.'))To add event listeners in your Astro components, you can use the above utility function. It expects the following parameters:
selector
: Pass a query selector as the first parameter where you want to attach the event listener. This can also be a variable that references an HTML element.event
: Pass the event for the event listener.callback
: Pass the callback function that should be executed once the event is triggered.
You can also use the
on
utility function to attach events listeners to multiple elements by setting the fourth parameter totrue
:Adding an event listener to all buttons import { on } from 'webcoreui'on('.my-buttons', 'click', () => console.log('Button clicked.'), true)This will query all elements with the
.my-buttons
selector, and add a click event listener to each one of them.
const get: (selector: string, all?: boolean) => Element | NodeListOf<Element> | nullconst on: ( selector: string | HTMLElement | Document, event: string, callback: any, all?: boolean) => void
Events
To work with custom events, use the dispatch
and listen
functions:
import { listen, dispatch } from 'webcoreui'
listen('theme-switched', theme => { console.log(theme) // 'theme-dark'})
dispatch('theme-switched', 'theme-dark')
listen
: Thelisten
function expects the name of the event as a string for the first parameter, and a callback function as the second parameter. The callback function has access to the payload sent by thedispatch
in the second parameter.dispatch
: To send the event, calldispatch
with the name of the event of your choice. In the second parameter, you can send a payload along with the event. Anylisten
call subscribed to the event will receive the payload when the event is triggered by thedispatch
call.
If you need to remove the listener later on, you can assign the listen
function to a variable, and call the remove
method:
import { listen, dispatch } from 'webcoreui'
const event = listen('theme-switched', theme => { console.log(theme) // 'theme-dark'})
dispatch('theme-switched', 'theme-dark')
// You can later remove the listener by calling .remove() on the eventevent.remove()
Use the two utility functions in combination to share data between different parts of your application that are otherwise unrelated. This approach is known as the publish-subscribe design pattern, or pub/sub for short.
const dispatch: (event: string, detail: unknown) => voidconst listen: (event: string, callback: (e: any) => unknown) => { remove: () => void}
Interactivity
Use the bodyFreeze
function to prevent the window from scrolling. This could be useful in cases you want to prevent scrolling when a popup or dialog blocks the main content.
import { bodyFreeze } from 'webcoreui'
bodyFreeze() // Freezes the window from scrollingbodyFreeze(false) // Unfreezes the window
const bodyFreeze: (freeze: boolean) => void
Interpolate
You can use the following math functions if you need to transform numbers in various ways:
clamp
: Restrict a value to lie within a specified range.lerp
: Find a value that is a given fraction between a start and end value.invlerp
: Find the fraction at which a given value lies between a start and end value.interpolate
: A combination oflerp
andinvlerp
to map values from one range to another.
-
Clamp
import { clamp } from 'webcoreui'// Clamp 50 between 0 and 100clamp(50, 0, 100) -> 50// Clamp 100 between 0 and 50clamp(100, 0, 50) -> 50// Clamp 50 between 100 and 200clamp(50, 100, 200) -> 100Use cases:
- User Input Validation: Ensuring that user inputs stay within a valid range, such as volume levels (0 to 100).
- Animation Control: Limiting the position or size of elements within the bounds of a container.
-
Lerp
import { lerp } from 'webcoreui'// 50% between 0 and 10lerp(0, 10, .5) -> 5// 50% between 0 and 100lerp(0, 100, .5) -> 50// 200% between 0 and 100lerp(0, 100, 2) -> 200// 20% between 100 and 200lerp(100, 200, .2) -> 120Use cases:
- Smooth Animations: Gradually moving an element from one position to another or transitioning between colors.
- Blending Values: Combining two values based on a weight.
-
Inverse Lerp
import { invlerp } from 'webcoreui'// Map 5 from [0, 10] to [0, 1]invlerp(0, 10, 5) -> .5// Map 50 from [0, 100] to [0, 1]invlerp(0, 100, 50) -> .5// Map 20 from [0, 100] to [0, 1]invlerp(0, 100, 20) -> .2// Map 120 from [100, 200] to [0, 1]invlerp(100, 200, 120) -> .2Use cases:
- Mapping Values: Mapping a value from one range to another, which is useful in normalization or data scaling.
- Progress Indicators: Determining the progress percentage of a task or loading bar based on the current value.
-
Interpolate
import { interpolate } from 'webcoreui'// Map 50 from [0, 100] to [0, 50]interpolate(50, [0, 100], [0, 50]) -> 25// Map 50 from [0, 100] to [100, 300]interpolate(50, [0, 100], [100, 300]) -> 200// Map 100 from [0, 200] to [0, 100]interpolate(100, [0, 200], [0, 100]) -> 50Use the
interpolate
function if you need to provide both the input and output ranges.
const clamp = (num: number, min: number, max: number) => numberconst lerp = (start: number, end: number, value: number) => numberconst invlerp = (start: number, end: number, value: number) => numberconst interpolate = ( value: number, input: [start: number, end: number], output: [start: number, end: number],) => number
Modals & Sheets
To open modals or sheets, you’ll need to create a Modal
/Sheet
component first:
<Button className="my-button">Open Modal</Button><Modal className="my-modal"> Modal with text only.</Modal>
<Button className="my-button">Open Sheet</Button><Sheet className="my-sheet"> Sheet with text only.</Sheet>
Based on the above selectors, you can target this component to trigger it using the modal
function:
import { modal } from 'webcoreui'
modal({ trigger: '.my-button', modal: '.my-modal'})
import { modal } from 'webcoreui'
const modalInstance = modal('.my-modal')
// On button clickmodalInstance.open()
import { closeModal } from 'webcoreui'
closeModal('.my-modal')
You can open modals in two different ways:
- Open: Pass a configuration object with a
trigger
property that specifies a query selector for a trigger element, and pass amodal
property to target theModal
/Sheet
component. Clicking on the trigger element will now open the component. - Open via JS: Pass a query selector to the
modal
function that targets the component, and assign the function to a variable. You can call theopen
method on the assigned variable. This lets you trigger the component programmatically, for example, after a network request finishes.
type ModalCallback = { trigger: Element | null modal: HTMLElement}
type Modal = { trigger: string modal: string onOpen?: (args: ModalCallback) => unknown onClose?: (args: ModalCallback) => unknown}
const modal: (config: Modal | string) => { open: () => void remove: () => void} | voidconst closeModal: (modal: string) => void
The JavaScript API of the Modal
and Sheet
components are identical. To learn more about how to use the Modal
component, visit its documentation. To learn more about how to use the Sheet
component, you can find its documentation here.
Popovers
To create popovers, you’ll need to create a Popover
component first:
<Button className="trigger-popover">Open popover</Button><Popover className="my-popover"> Popover with text only.</Popover>
As popovers are attached to interactive elements, you’ll also need to create an interactive element, such as a button, that can trigger the popover. In this example, a Button
component is used.
Based on the above selectors, you can target this popover to initialize it:
import { popover } from 'webcoreui'
popover({ trigger: '.trigger-popover', // Query selector for the button popover: '.my-popover' // Query selector for the popover})
import { closePopover } from 'webcoreui'
closePopover('.my-popover')
import { popover } from 'webcoreui'
const popoverInstance = popover({ trigger: '.trigger-popover', popover: '.my-popover'})
// Calling `.remove` will disable the popoverpopoverInstance.remove()
Whenever the .trigger-popover
button is clicked, it’ll open the .my-popover
element. The popover
function also returns a remove
function that can be used to remove the created popover instance.
type PopoverPosition = 'top' | 'top-start' | 'top-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end'
type PopoverCallback = { trigger: HTMLElement popover: HTMLElement position: PopoverPosition | undefined}
type Popover = { trigger: string popover: string position?: PopoverPosition offset?: number closeOnBlur?: boolean closeOnEsc?: boolean onOpen?: (args: PopoverCallback) => unknown onClose?: (args: PopoverCallback) => unknown}
const closePopover: (selector: string) => voidconst popover: (config: Popover) => { remove: () => void} | void
To learn more about how to use the Popover
component, visit its documentation.
Toasts
To dynamically show toasts, you’ll need to create a Toast
component first:
<Toast className="my-toast"> Toast with text only.</Toast>
Based on a selector, you can target this toast to trigger it:
import { toast } from 'webcoreui'
toast('.my-toast')
import { hideToast } from 'webcoreui'
hideToast('.my-toast')
import { setDefaultTimeout } from 'webcoreui'
setDefaultTimeout(3000)
To configure the behavior of your toast, pass a configuration object to the toast
function:
import { toast } from 'webcoreui'
toast({ element: '.my-toast', timeout: 10_000, title: 'Title set through JS', content: 'Content updated with JavaScript', position: 'bottom-left'})
type Toast = { element: string timeout?: number title?: string content?: string position?: 'bottom-left' | 'top-left' | 'top-right' | 'bottom-full' | 'top-full'}
const setDefaultTimeout: (time: number) => numberconst toast: (config: Toast | string) => voidconst hideToast: (element: string) => void
To learn more about how to use the Toast
component, visit its documentation.
Request improvement for this page