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;