Skip to main content
Glama
deleonio
by deleonio
Alert.tsx3.31 kB
import { type FunctionalComponent as FC, h } from '@stencil/core'; import { type JSXBase } from '@stencil/core/internal'; import clsx from 'clsx'; import { KolButtonWcTag } from '../../core/component-names'; import { translate } from '../../i18n'; import { type InternalAlertProps } from '../../schema'; import AlertIcon from '../AlertIcon'; import KolHeadingFc from '../Heading'; import { genBemAlert as bem, BEM_CLASS_ALERT__CLOSER, BEM_CLASS_ALERT__CONTENT } from './bem'; const translateCloseAlert = translate('kol-close-alert'); export type KolAlertFcProps = JSXBase.HTMLAttributes<HTMLDivElement> & Partial<Omit<InternalAlertProps, 'on'>> & { onCloserClick?: () => void; onAlertTimeout?: () => void; }; /** * - https://developer.mozilla.org/de/docs/Web/API/Navigator/vibrate * - https://googlechrome.github.io/samples/vibration/ * - Ongoing discussion: https://github.com/public-ui/kolibri/issues/7191 * @todo Move side-effect out of render-function to avoid multiple incarnations. */ const vibrateOnError = (): void => { if (typeof navigator === 'undefined' || typeof navigator.vibrate !== 'function') { return; } const ua = navigator.userActivation; const hasGesture = ua?.isActive || ua?.hasBeenActive; if (!hasGesture) { return; } if (!matchMedia('(any-pointer: coarse)').matches) { return; } try { navigator.vibrate([100, 75, 100, 75, 100]); } catch { /* no-op */ } }; const KolAlertFc: FC<KolAlertFcProps> = (props, children) => { const { class: classNames = {}, alert = false, hasCloser = false, label, level = 0, type = 'default', variant = 'msg', onAlertTimeout, onCloserClick, ...other } = props; if (alert) { vibrateOnError(); setTimeout(() => { onAlertTimeout?.(); }, 10000); } /** * Define the dynamic BEM class names for the alert component. */ const BEM_CLASS_ROOT = bem('kol-alert', { hasCloser: !!hasCloser, [`type-${type}`]: true, [`variant-${variant}`]: true, }); const BEM_CLASS__HEADING = bem('kol-alert', 'heading', { [`h${level}`]: true, }); const rootProps: Partial<JSXBase.HTMLAttributes<HTMLDivElement>> = { class: clsx(classNames, BEM_CLASS_ROOT), ...other, }; return ( <div role={alert ? 'alert' : undefined} {...rootProps} data-testid="alert"> <div class="kol-alert__container"> <AlertIcon label={label} type={type} /> <div class="kol-alert__container-content"> {label && ( <KolHeadingFc class={BEM_CLASS__HEADING} level={level} id="heading"> {label} </KolHeadingFc> )} {variant === 'msg' && ( <span class={BEM_CLASS_ALERT__CONTENT} aria-describedby={label ? 'heading' : undefined}> {children} </span> )} </div> {hasCloser && ( <KolButtonWcTag class={BEM_CLASS_ALERT__CLOSER} data-testid="alert-close-button" _ariaDescription={label?.trim() || ''} _hideLabel _icons={{ left: { icon: 'codicon codicon-close', }, }} _label={translateCloseAlert} _on={{ onClick: onCloserClick }} _tooltipAlign="left" /> )} </div> {variant === 'card' && ( <div class={BEM_CLASS_ALERT__CONTENT} aria-describedby={label ? 'heading' : undefined}> {children} </div> )} </div> ); }; export default KolAlertFc;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/deleonio/public-ui-kolibri'

If you have feedback or need assistance with the MCP directory API, please join our Discord server