Files
WRNexusJS/packages/ui/components/alert.wrn
T
Clintchiz 2c960fc1dc
Quality / quality (ubuntu-latest) (push) Failing after 9m49s
Quality / quality (windows-latest) (push) Canceled after 0s
refactor: migrate legacy wire namespace to wrn
2026-08-12 18:51:15 +05:30

463 lines
12 KiB
Plaintext

component Alert {
outputs {
dismiss(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
action(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
}
props {
size: string = "default"
color: string = "info"
variant: string = "soft"
class: string = ""
radius: string = "md"
shadow: string = "sm"
title: string = "Alert"
description: string = ""
items: unknown[] = []
actions: unknown[] = []
showIcon: boolean = false
icon: string = ""
dismissible: boolean = false
dismissLabel: string = "Dismiss alert"
role: string = "alert"
live: string = "polite"
linkLabel: string = ""
linkHref: string = ""
actionLabel: string = ""
actionHref: string = ""
compact: boolean = false
}
state visible: boolean = true
functions {
// The output name has to be written out rather than computed: outputs are
// resolved as named properties, so a dynamic key would not reach a parent
// binding. Only two names exist here, so a branch is honest and cheap.
client function dispatchAlertEvent(sourceEvent, eventName, action, payload) {
payload = {
component: "Alert",
title: title,
color: color,
variant: variant,
action: action
}
if (eventName === "dismiss") {
output.dismiss(payload)
} else {
output.action(payload)
}
}
client function dismissAlert(sourceEvent) {
visible = false
dispatchAlertEvent(sourceEvent, "dismiss", null)
}
client function selectAction(sourceEvent, action) {
dispatchAlertEvent(sourceEvent, "action", action)
}
}
view {
<section
{...attrs}
data-wrn-alert
data-color="{color}"
data-variant="{variant}"
data-radius="{radius}"
data-shadow="{shadow}"
data-show="visible"
aria-hidden="{visible ? 'false' : 'true'}"
role="{role}"
aria-live="{live}"
class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--alert wrn-next--alert-{variant} {compact ? 'wrn-next--alert-compact' : ''} {class}"
>
{#if showIcon}
<span class="wrn-next__alert-icon" aria-hidden="true">
{#if icon}
<span class="{icon}"></span>
{:else if color === "success"}
<span class="icon-[lucide--circle-check]"></span>
{:else if color === "danger"}
<span class="icon-[lucide--circle-x]"></span>
{:else if color === "warning"}
<span class="icon-[lucide--triangle-alert]"></span>
{:else}
<span class="icon-[lucide--info]"></span>
{/if}
</span>
{/if}
<div class="wrn-next__alert-body">
{#if title}<strong class="wrn-next__alert-title">{title}</strong>{/if}
{#if description}<p>{description}</p>{/if}
{#if items.length > 0}
<ul>
{#each items as item}<li>{item.label || item}</li>{/each}
</ul>
{/if}
{#if actions.length > 0 || actionLabel || linkLabel}
<div class="wrn-next__alert-actions">
{#each actions as item}
<a
href="{item.href || '#'}"
data-variant="{item.variant || 'link'}"
@click="selectAction(event, item)"
>{item.label}</a>
{/each}
{#if actionLabel}
<a
href="{actionHref || '#'}"
data-variant="action"
@click="selectAction(event, { label: actionLabel, href: actionHref })"
>{actionLabel}</a>
{/if}
{#if linkLabel}
<a
href="{linkHref || '#'}"
data-variant="link"
@click="selectAction(event, { label: linkLabel, href: linkHref })"
>{linkLabel}</a>
{/if}
</div>
{/if}
</div>
{#if dismissible}
<button
type="button"
class="wrn-next__alert-dismiss"
aria-label="{dismissLabel}"
@click="dismissAlert(event)"
>
<span class="icon-[lucide--x]" aria-hidden="true"></span>
</button>
{/if}
</section>
}
style {
.wrn-next--alert-soft {
border-color: color-mix(in srgb, var(--wrn-alert-color) 45%, var(--wrn-color-border));
background: var(--wrn-alert-soft);
}
.wrn-next--alert-soft .wrn-next__alert-title,
.wrn-next--alert-soft .wrn-next__alert-icon,
.wrn-next--alert-soft .wrn-next__alert-actions a {
color: var(--wrn-alert-color);
}
.wrn-next--alert-solid {
border-color: var(--wrn-alert-color);
background: var(--wrn-alert-color);
color: white;
}
.wrn-next--alert.wrn-next--alert-solid
:is(
.wrn-next__alert-title,
.wrn-next__alert-body > p,
.wrn-next__alert-body li,
.wrn-next__alert-actions a,
.wrn-next__alert-icon
) {
color: currentColor;
}
.wrn-next--alert-solid[data-color="light"] {
color: #18181b;
}
.wrn-next--alert-solid[data-color="warning"] {
color: #18181b;
}
.wrn-next--alert-bordered {
border-color: var(--wrn-alert-color);
background: var(--wrn-color-surface);
}
.wrn-next--alert-bordered .wrn-next__alert-title,
.wrn-next--alert-bordered .wrn-next__alert-icon,
.wrn-next--alert-bordered .wrn-next__alert-actions a {
color: var(--wrn-alert-color);
}
.wrn-next--alert-accent {
border-color: color-mix(in srgb, var(--wrn-alert-color) 35%, var(--wrn-color-border));
border-left: 4px solid var(--wrn-alert-color);
background: var(--wrn-alert-soft);
}
.wrn-next--alert-accent .wrn-next__alert-title,
.wrn-next--alert-accent .wrn-next__alert-icon,
.wrn-next--alert-accent .wrn-next__alert-actions a {
color: var(--wrn-alert-color);
}
.wrn-next--alert {
--wrn-alert-color: var(--wrn-component-color);
--wrn-alert-soft: color-mix(in srgb, var(--wrn-alert-color) 16%, var(--wrn-color-surface));
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 0.8rem;
width: 100%;
padding: 1rem;
border: 1px solid transparent;
border-radius: var(--wrn-radius, 0.75rem);
color: var(--wrn-color-text);
}
.wrn-next--alert[data-radius="none"] {
border-radius: 0;
}
.wrn-next--alert[data-radius="sm"] {
border-radius: var(--wrn-radius-sm, 0.375rem);
}
.wrn-next--alert[data-radius="lg"] {
border-radius: calc(var(--wrn-radius, 0.75rem) * 1.35);
}
.wrn-next--alert[data-radius="xl"] {
border-radius: calc(var(--wrn-radius, 0.75rem) * 1.75);
}
.wrn-next--alert[data-shadow="none"] {
box-shadow: none;
}
.wrn-next--alert[data-shadow="sm"] {
box-shadow: 0 6px 16px color-mix(in srgb, #000 14%, transparent);
}
.wrn-next--alert[data-shadow="md"] {
box-shadow:
0 2px 6px color-mix(in srgb, #000 10%, transparent),
0 12px 28px color-mix(in srgb, #000 18%, transparent);
}
.wrn-next--alert[data-shadow="lg"] {
box-shadow:
0 4px 10px color-mix(in srgb, #000 12%, transparent),
0 20px 48px color-mix(in srgb, #000 24%, transparent);
}
.wrn-next--alert[data-color="secondary"] {
--wrn-alert-color: #737373;
}
.wrn-next--alert[data-color="success"] {
--wrn-alert-color: #0f9f8f;
}
.wrn-next--alert[data-color="danger"] {
--wrn-alert-color: #dc3545;
}
.wrn-next--alert[data-color="warning"] {
--wrn-alert-color: #eab308;
}
.wrn-next--alert[data-color="info"] {
--wrn-alert-color: #2563eb;
}
.wrn-next--alert[data-color="dark"] {
--wrn-alert-color: #27272a;
}
.wrn-next--alert[data-color="light"] {
--wrn-alert-color: #f4f4f5;
}
.wrn-next--alert-compact {
padding: 0.75rem 0.9rem;
}
.wrn-next--alert-compact:not(:has(.wrn-next__alert-icon)):not(:has(.wrn-next__alert-dismiss)) {
grid-template-columns: minmax(0, 1fr);
}
.wrn-next--alert-compact .wrn-next__alert-body {
display: block;
}
.wrn-next--alert-compact .wrn-next__alert-title {
margin-right: 0.25rem;
}
.wrn-next--alert-compact .wrn-next__alert-body > p {
display: inline;
}
.wrn-next__alert-icon {
display: inline-grid;
width: 1.25rem;
height: 1.25rem;
place-items: center;
margin-top: 0.05rem;
color: var(--wrn-alert-color);
}
.wrn-next__alert-icon > span {
width: 1rem;
height: 1rem;
}
.wrn-next__alert-body {
display: grid;
min-width: 0;
gap: 0.35rem;
}
.wrn-next__alert-title {
font-size: 0.88rem;
line-height: 1.45;
}
.wrn-next__alert-body > p,
.wrn-next__alert-body li {
color: inherit;
font-size: 0.8rem;
line-height: 1.55;
}
.wrn-next__alert-body > ul {
display: grid;
gap: 0.25rem;
margin: 0.15rem 0 0;
padding-left: 1.25rem;
}
.wrn-next__alert-actions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1rem;
margin-top: 0.35rem;
}
.wrn-next__alert-actions a {
color: var(--wrn-alert-color);
font-size: 0.78rem;
font-weight: 700;
text-decoration: none;
}
.wrn-next__alert-actions a:hover {
text-decoration: underline;
}
.wrn-next__alert-actions a[data-variant="action"] {
padding: 0.35rem 0.6rem;
border-radius: var(--wrn-radius-sm);
background: var(--wrn-alert-color);
color: white;
text-decoration: none;
}
.wrn-next__alert-dismiss {
display: inline-grid;
width: 1.75rem;
height: 1.75rem;
place-items: center;
padding: 0;
border: 0;
border-radius: var(--wrn-radius-sm);
background: transparent;
color: currentColor;
cursor: pointer;
}
.wrn-next__alert-dismiss:hover {
background: color-mix(in srgb, currentColor 10%, transparent);
}
.wrn-next__alert-dismiss:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
@media (max-width: 36rem) {
.wrn-next--alert {
grid-template-columns: auto minmax(0, 1fr);
}
.wrn-next__alert-dismiss {
grid-column: 2;
grid-row: 1;
justify-self: end;
}
}
/* Shared component foundation. */
.wrn-component {
--wrn-component-color: var(--wrn-color-primary);
--wrn-component-scale: 1;
margin: 0;
color: var(--wrn-color-text);
font-family: var(--wrn-font-sans, inherit);
}
.wrn-component--color-primary {
--wrn-component-color: var(--wrn-color-primary);
}
.wrn-component--color-secondary {
--wrn-component-color: var(--wrn-color-secondary);
}
.wrn-component--color-success {
--wrn-component-color: var(--wrn-color-success);
}
.wrn-component--color-warning {
--wrn-component-color: var(--wrn-color-warning);
}
.wrn-component--color-danger {
--wrn-component-color: var(--wrn-color-danger);
}
.wrn-component--color-info {
--wrn-component-color: var(--wrn-color-info);
}
.wrn-component--size-xs {
--wrn-component-scale: 0.78;
}
.wrn-component--size-sm {
--wrn-component-scale: 0.88;
}
.wrn-component--size-default,
.wrn-component--size-md {
--wrn-component-scale: 1;
}
.wrn-component--size-lg {
--wrn-component-scale: 1.14;
}
.wrn-component--size-xl {
--wrn-component-scale: 1.28;
}
.wrn-component:not(.wrn-btn) {
font-size: calc(1em * var(--wrn-component-scale));
}
.wrn-component :is(a, button, input, select, textarea):focus-visible {
outline-color: var(--wrn-component-color);
}
.wrn-component p {
margin: 0;
color: var(--wrn-color-muted);
line-height: 1.6;
}
}
}