237 lines
6.6 KiB
Plaintext
237 lines
6.6 KiB
Plaintext
import AdvancedSelect from "@wrnexus/ui/components/AdvancedSelect.wrn"
|
|
import ComboBox from "@wrnexus/ui/components/Combobox.wrn"
|
|
|
|
// Component event test page. Route: /test
|
|
//
|
|
// Events bubble from the exact ComboBox or AdvancedSelect that emitted them.
|
|
// The <section> below listens once for every child component, while the first
|
|
// ComboBox also demonstrates a listener attached directly to one component.
|
|
page Test {
|
|
layout = "public"
|
|
|
|
state teams = [{ value: "design", label: "Design", description: "Product and visual design", icon: "icon-[lucide--palette]" }, { value: "engineering", label: "Engineering", description: "Platform engineering", icon: "icon-[lucide--code-2]" }, { value: "growth", label: "Growth", description: "Marketing and customer growth", icon: "icon-[lucide--trending-up]" }, { value: "support", label: "Support", description: "Customer operations", icon: "icon-[lucide--life-buoy]" }]
|
|
state eventName = "No event yet"
|
|
state eventSource = "Interact with a component"
|
|
state eventPayload = "{}"
|
|
state selectedTeam = ""
|
|
|
|
seo {
|
|
title = "Component event test"
|
|
description = "Test ComboBox and AdvancedSelect events on one WRN page."
|
|
canonical = "/test"
|
|
}
|
|
|
|
functions {
|
|
function handleComponentEvent(event) {
|
|
eventName = event.type
|
|
eventSource = event.target.getAttribute("data-field") || event.detail.component
|
|
eventPayload = JSON.stringify(event.detail, null, 2)
|
|
}
|
|
|
|
function handleTeamSelect(event) {
|
|
selectedTeam = event.detail.value
|
|
}
|
|
}
|
|
|
|
view {
|
|
<header class="test-hero">
|
|
<span>WRN component events</span>
|
|
<h1>ComboBox and AdvancedSelect event test</h1>
|
|
<p>
|
|
This page contains multiple component instances. Every component has a
|
|
unique <code>id</code> and <code>data-field</code>, so the event source
|
|
is always identifiable.
|
|
</p>
|
|
</header>
|
|
|
|
<!--
|
|
Event delegation: these eight listeners receive events from every
|
|
ComboBox and AdvancedSelect inside this section because the custom events
|
|
bubble from their component roots.
|
|
-->
|
|
<section
|
|
class="test-grid"
|
|
@search="handleComponentEvent(event)"
|
|
@select="handleComponentEvent(event)"
|
|
@change="handleComponentEvent(event)"
|
|
@clear="handleComponentEvent(event)"
|
|
@open="handleComponentEvent(event)"
|
|
@close="handleComponentEvent(event)"
|
|
@load="handleComponentEvent(event)"
|
|
@error="handleComponentEvent(event)"
|
|
>
|
|
<article class="test-card">
|
|
<span class="test-card__type">Direct listener</span>
|
|
<h2>Team ComboBox</h2>
|
|
<p>
|
|
Its <code>@select</code> listener updates the selected-team
|
|
text below. The delegated section listener also receives the event.
|
|
</p>
|
|
|
|
<ComboBox
|
|
id="team-combobox"
|
|
data-field="team-combobox"
|
|
name="team"
|
|
label="Choose a team"
|
|
placeholder="Search teams"
|
|
options="{teams}"
|
|
optionTemplate="icon"
|
|
@select="handleTeamSelect(event)"
|
|
/>
|
|
|
|
<output class="test-selection">
|
|
Selected team: {selectedTeam || "None"}
|
|
</output>
|
|
</article>
|
|
|
|
<article class="test-card">
|
|
<span class="test-card__type">Second instance</span>
|
|
<h2>Reviewer ComboBox</h2>
|
|
<p>
|
|
This is another ComboBox on the same page. Its events remain
|
|
distinguishable through <code>data-field="reviewer-combobox"</code>.
|
|
</p>
|
|
|
|
<ComboBox
|
|
id="reviewer-combobox"
|
|
data-field="reviewer-combobox"
|
|
name="reviewer"
|
|
label="Choose a reviewer team"
|
|
placeholder="Search reviewer teams"
|
|
options="{teams}"
|
|
/>
|
|
</article>
|
|
|
|
<article class="test-card">
|
|
<span class="test-card__type">Multiple selection</span>
|
|
<h2>Project teams</h2>
|
|
<p>
|
|
AdvancedSelect emits the same event names. Multiple values are
|
|
available through <code>event.detail.values</code>.
|
|
</p>
|
|
|
|
<AdvancedSelect
|
|
id="project-teams"
|
|
data-field="project-teams"
|
|
name="projectTeams"
|
|
label="Assign project teams"
|
|
placeholder="Choose one or more teams"
|
|
options="{teams}"
|
|
multiple
|
|
showCounter
|
|
maxSelections="3"
|
|
optionTemplate="icon"
|
|
/>
|
|
</article>
|
|
|
|
<aside class="event-monitor" aria-live="polite">
|
|
<div>
|
|
<span>Latest event</span>
|
|
<strong>{eventName}</strong>
|
|
</div>
|
|
<div>
|
|
<span>Source component</span>
|
|
<strong>{eventSource}</strong>
|
|
</div>
|
|
<pre><code>{eventPayload}</code></pre>
|
|
</aside>
|
|
</section>
|
|
}
|
|
|
|
style {
|
|
.test-hero {
|
|
display: grid;
|
|
max-width: 52rem;
|
|
gap: 0.75rem;
|
|
margin-block: 3rem 2rem;
|
|
}
|
|
|
|
.test-hero > span,
|
|
.test-card__type,
|
|
.event-monitor span {
|
|
color: var(--wrn-color-primary);
|
|
font-size: 0.72rem;
|
|
font-weight: 800;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.test-hero h1,
|
|
.test-card h2,
|
|
.test-hero p,
|
|
.test-card p {
|
|
margin: 0;
|
|
}
|
|
|
|
.test-hero p,
|
|
.test-card p {
|
|
color: var(--wrn-color-muted);
|
|
line-height: 1.65;
|
|
}
|
|
|
|
.test-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: 1rem;
|
|
margin-bottom: 4rem;
|
|
}
|
|
|
|
.test-card,
|
|
.event-monitor {
|
|
display: grid;
|
|
align-content: start;
|
|
gap: 1rem;
|
|
padding: clamp(1rem, 3vw, 1.5rem);
|
|
border: 1px solid var(--wrn-color-border);
|
|
border-radius: var(--wrn-radius-lg);
|
|
background: var(--wrn-color-surface);
|
|
box-shadow: var(--wrn-shadow-1);
|
|
}
|
|
|
|
.test-selection {
|
|
color: var(--wrn-color-muted);
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
.event-monitor {
|
|
position: sticky;
|
|
bottom: 1rem;
|
|
grid-column: 1 / -1;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
background: color-mix(in srgb, var(--wrn-color-surface) 94%, var(--wrn-color-primary));
|
|
}
|
|
|
|
.event-monitor > div {
|
|
display: grid;
|
|
gap: 0.35rem;
|
|
}
|
|
|
|
.event-monitor pre {
|
|
grid-column: 1 / -1;
|
|
max-height: 18rem;
|
|
overflow: auto;
|
|
margin: 0;
|
|
padding: 1rem;
|
|
border-radius: var(--wrn-radius-md);
|
|
background: var(--wrn-color-bg);
|
|
font-size: 0.75rem;
|
|
line-height: 1.65;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
@media (max-width: 760px) {
|
|
.test-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.event-monitor {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.event-monitor pre {
|
|
grid-column: auto;
|
|
}
|
|
}
|
|
}
|
|
}
|