Files
WRNexusJS/packages/ui/components/Breadcrumb.wrn
T

353 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
component Breadcrumb {
outputs {
select(payload: { value?: string | number | boolean | null; values?: Array<string | number | boolean | null | object>; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null)
}
props {
label: string = "Breadcrumb"
items: unknown[] = []
active: string = ""
activeIcon: string = "icon-[lucide--file-text]"
separator: string = "chevron"
showHome: boolean = false
homeLabel: string = "Home"
homeHref: string = "/"
homeIcon: string = "icon-[lucide--house]"
size: string = "default"
color: string = "primary"
variant: string = "minimal"
class: string = ""
}
view {
<nav
{...attrs}
data-ui-component="Breadcrumb"
data-size='{size}'
data-color='{color}'
data-variant='{variant}'
aria-label='{label}'
class='wrn-breadcrumb {class}'
data-wrn-owner="Breadcrumb" data-wrn-part="root" data-wrn-component="Breadcrumb" data-wrn-axis-size='{size}' data-wrn-axis-color='{color}' data-wrn-axis-variant='{variant}'>
<ol class="wrn-breadcrumb__list" data-wrn-owner="Breadcrumb" data-wrn-part="list" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if showHome}
<li class="wrn-breadcrumb__item wrn-breadcrumb__item--home" data-wrn-owner="Breadcrumb" data-wrn-part="item" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
<a
href='{homeHref || "/"}'
class="wrn-breadcrumb__link wrn-breadcrumb__home"
@click='output.select({ item: { label: homeLabel, href: homeHref || "/", value: "home" }, itemIndex: -1 })'
data-wrn-owner="Breadcrumb" data-wrn-part="link" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if homeIcon === "icon-[lucide--house]"}
<span class="icon-[lucide--house] wrn-breadcrumb__icon" aria-hidden="true" data-wrn-owner="Breadcrumb" data-wrn-part="icon" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></span>
{:else if homeIcon}
<span class='{homeIcon} wrn-breadcrumb__icon' aria-hidden="true" data-wrn-owner="Breadcrumb" data-wrn-part="icon" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></span>
{/if}
<span class="wrn-breadcrumb__home-label" data-wrn-owner="Breadcrumb" data-wrn-part="homeLabel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{homeLabel}</span>
</a>
</li>
{/if}
{#each items as item, itemIndex}
<li
class="wrn-breadcrumb__item"
data-current='{item.active || item.current || (active && active === (item.value || item.label || item.title)) || (!active && itemIndex === items.length - 1) ? "true" : "false"}'
data-wrn-owner="Breadcrumb" data-wrn-part="item" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if showHome || itemIndex > 0}
<span class="wrn-breadcrumb__separator" aria-hidden="true" data-wrn-owner="Breadcrumb" data-wrn-part="separator" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if separator === "slash"}
<span>/</span>
{:else if separator === "dot"}
<span>•</span>
{:else if separator === "arrow"}
<span>→</span>
{:else}
<span class="wrn-breadcrumb__separator-icon" data-wrn-owner="Breadcrumb" data-wrn-part="separatorIcon" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">›</span>
{/if}
</span>
{/if}
{#if item.href && !item.disabled && !(item.active || item.current || (active && active === (item.value || item.label || item.title)) || (!active && itemIndex === items.length - 1))}
<a
href='{item.href}'
target='{item.target || ""}'
rel='{item.external ? "noopener noreferrer" : (item.rel || "")}'
class="wrn-breadcrumb__link"
@click='output.select({ item: item, itemIndex: itemIndex })'
data-wrn-owner="Breadcrumb" data-wrn-part="link" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if item.icon}
<span class='{item.icon} wrn-breadcrumb__icon' aria-hidden="true" data-wrn-owner="Breadcrumb" data-wrn-part="icon" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></span>
{/if}
<span class="wrn-breadcrumb__label" data-wrn-owner="Breadcrumb" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{item.label || item.title}</span>
{#if item.external}
<span class="icon-[lucide--arrow-up-right] wrn-breadcrumb__external" aria-hidden="true" data-wrn-owner="Breadcrumb" data-wrn-part="external" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></span>
{/if}
</a>
{:else}
<span
class="wrn-breadcrumb__current"
aria-current='{item.active || item.current || (active && active === (item.value || item.label || item.title)) || (!active && itemIndex === items.length - 1) ? "page" : "false"}'
aria-disabled='{item.disabled ? "true" : "false"}'
data-wrn-owner="Breadcrumb" data-wrn-part="current" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if item.icon}
<span class='{item.icon} wrn-breadcrumb__icon' aria-hidden="true" data-wrn-owner="Breadcrumb" data-wrn-part="icon" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></span>
{/if}
<span class="wrn-breadcrumb__label" data-wrn-owner="Breadcrumb" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{item.label || item.title}</span>
</span>
{/if}
</li>
{/each}
{#if active && !items.some((item) => active === (item.value || item.label || item.title))}
<li class="wrn-breadcrumb__item" data-current="true" data-wrn-owner="Breadcrumb" data-wrn-part="item" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if showHome || items.length > 0}
<span class="wrn-breadcrumb__separator" aria-hidden="true" data-wrn-owner="Breadcrumb" data-wrn-part="separator" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if separator === "slash"}
<span>/</span>
{:else if separator === "dot"}
<span>•</span>
{:else if separator === "arrow"}
<span>→</span>
{:else}
<span class="wrn-breadcrumb__separator-icon" data-wrn-owner="Breadcrumb" data-wrn-part="separatorIcon" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">›</span>
{/if}
</span>
{/if}
<span class="wrn-breadcrumb__current" aria-current="page" data-wrn-owner="Breadcrumb" data-wrn-part="current" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
{#if activeIcon}
<span class='{activeIcon} wrn-breadcrumb__icon' aria-hidden="true" data-wrn-owner="Breadcrumb" data-wrn-part="icon" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></span>
{/if}
<span class="wrn-breadcrumb__label" data-wrn-owner="Breadcrumb" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{active}</span>
</span>
</li>
{/if}
</ol>
</nav>
}
style {
.wrn-breadcrumb {
--breadcrumb-accent: var(--wrn-color-primary);
--breadcrumb-soft: var(--wrn-color-primary-soft);
--breadcrumb-muted: var(--wrn-color-primary-muted);
--breadcrumb-text: var(--wrn-color-primary-text);
min-width: 0;
max-width: 100%;
color: var(--wrn-color-text-muted);
}
.wrn-breadcrumb[data-color="secondary"] {
--breadcrumb-accent: var(--wrn-color-secondary);
--breadcrumb-soft: var(--wrn-color-secondary-soft);
--breadcrumb-muted: var(--wrn-color-secondary-muted);
--breadcrumb-text: var(--wrn-color-secondary-text);
}
.wrn-breadcrumb[data-color="info"] {
--breadcrumb-accent: var(--wrn-color-info);
--breadcrumb-soft: var(--wrn-color-info-soft);
--breadcrumb-muted: var(--wrn-color-info-muted);
--breadcrumb-text: var(--wrn-color-info-text);
}
.wrn-breadcrumb[data-color="success"] {
--breadcrumb-accent: var(--wrn-color-success);
--breadcrumb-soft: var(--wrn-color-success-soft);
--breadcrumb-muted: var(--wrn-color-success-muted);
--breadcrumb-text: var(--wrn-color-success-text);
}
.wrn-breadcrumb[data-color="warning"] {
--breadcrumb-accent: var(--wrn-color-warning);
--breadcrumb-soft: var(--wrn-color-warning-soft);
--breadcrumb-muted: var(--wrn-color-warning-muted);
--breadcrumb-text: var(--wrn-color-warning-text);
}
.wrn-breadcrumb[data-color="danger"] {
--breadcrumb-accent: var(--wrn-color-danger);
--breadcrumb-soft: var(--wrn-color-danger-soft);
--breadcrumb-muted: var(--wrn-color-danger-muted);
--breadcrumb-text: var(--wrn-color-danger-text);
}
.wrn-breadcrumb[data-variant="soft"] {
width: fit-content;
max-width: 100%;
padding: 0.25rem 0.5rem;
background: var(--wrn-color-surface-soft, var(--breadcrumb-soft));
border: 1px solid var(--wrn-color-border);
border-radius: var(--wrn-radius-sm);
}
.wrn-breadcrumb[data-variant="outline"] {
width: fit-content;
max-width: 100%;
padding: 0.25rem 0.5rem;
background: var(--wrn-color-surface-raised);
border: 1px solid var(--wrn-color-border);
border-radius: var(--wrn-radius-sm);
box-shadow: var(--wrn-shadow-1);
}
.wrn-breadcrumb[data-variant="contrast"] {
color: rgba(255, 255, 255, 0.78);
}
.wrn-breadcrumb__list {
display: flex;
align-items: center;
gap: 0;
min-width: 0;
margin: 0;
padding: 0;
overflow-x: auto;
list-style: none;
scrollbar-width: none;
white-space: nowrap;
}
.wrn-breadcrumb__list::-webkit-scrollbar {
display: none;
}
.wrn-breadcrumb__item {
display: inline-flex;
align-items: center;
min-width: 0;
flex: 0 0 auto;
}
.wrn-breadcrumb__separator {
display: inline-flex;
align-items: center;
justify-content: center;
margin-inline: 0.25rem;
color: var(--wrn-color-border-strong, var(--wrn-color-text-subtle));
font-size: 0.75rem;
}
.wrn-breadcrumb__separator-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 0.9rem;
height: 0.9rem;
font-size: 1rem;
font-weight: 700;
line-height: 1;
}
.wrn-breadcrumb__link,
.wrn-breadcrumb__current {
display: inline-flex;
align-items: center;
gap: 0.375rem;
min-width: 0;
min-height: 1.75rem;
padding: 0.125rem 0.375rem;
border-radius: calc(var(--wrn-radius-sm) - 2px);
font-size: 0.8125rem;
line-height: 1.25rem;
text-decoration: none;
}
.wrn-breadcrumb[data-size="sm"] .wrn-breadcrumb__link,
.wrn-breadcrumb[data-size="sm"] .wrn-breadcrumb__current {
min-height: 1.75rem;
font-size: 0.75rem;
}
.wrn-breadcrumb[data-size="lg"] .wrn-breadcrumb__link,
.wrn-breadcrumb[data-size="lg"] .wrn-breadcrumb__current {
min-height: 2.25rem;
font-size: 0.875rem;
}
.wrn-breadcrumb__link {
color: var(--wrn-color-text-muted);
font-weight: 500;
transition: color 120ms ease, background 120ms ease;
}
.wrn-breadcrumb__link:hover {
color: var(--wrn-color-text);
background: var(--wrn-color-surface-muted, var(--breadcrumb-soft));
}
.wrn-breadcrumb__link:focus-visible {
color: var(--breadcrumb-accent);
outline: 2px solid var(--breadcrumb-accent);
outline-offset: 2px;
}
.wrn-breadcrumb__current {
max-width: 22rem;
color: var(--wrn-color-text);
font-weight: 600;
}
.wrn-breadcrumb__item[data-current="true"] .wrn-breadcrumb__current {
color: var(--wrn-color-text);
background: transparent;
}
.wrn-breadcrumb__current[aria-disabled="true"] {
opacity: 0.58;
}
.wrn-breadcrumb__icon,
.wrn-breadcrumb__external {
flex: 0 0 auto;
width: 0.95rem;
height: 0.95rem;
}
.wrn-breadcrumb__home {
color: var(--wrn-color-text-muted);
}
.wrn-breadcrumb__label {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
.wrn-breadcrumb[data-variant="contrast"] .wrn-breadcrumb__link,
.wrn-breadcrumb[data-variant="contrast"] .wrn-breadcrumb__current,
.wrn-breadcrumb[data-variant="contrast"] .wrn-breadcrumb__home {
color: inherit;
}
.wrn-breadcrumb[data-variant="contrast"] .wrn-breadcrumb__link:hover,
.wrn-breadcrumb[data-variant="contrast"] .wrn-breadcrumb__item[data-current="true"] .wrn-breadcrumb__current {
color: #ffffff;
background: rgba(255, 255, 255, 0.12);
}
.wrn-breadcrumb[data-variant="contrast"] .wrn-breadcrumb__separator {
color: rgba(255, 255, 255, 0.62);
}
@media (max-width: 639px) {
.wrn-breadcrumb__home-label {
display: none;
}
.wrn-breadcrumb__current {
max-width: 13rem;
}
}
@media (prefers-reduced-motion: reduce) {
.wrn-breadcrumb__link {
transition: none;
}
}
}
}