Refresh UI components and showcase; release updated framework packages
This commit is contained in:
1 parent
d800228585
commit
c77f5e1cec
293 files changed
+22544
-35778
No files matched your search
@@ -77,7 +77,7 @@ component Accordion {
|
||||
wasOpen = isOpen(value)
|
||||
|
||||
if (wasOpen) {
|
||||
openValues = openValues.filter((entry) => entry !== value)
|
||||
openValues = openValues.slice(0, openValues.indexOf(value)).concat(openValues.slice(openValues.indexOf(value) + 1))
|
||||
} else if (allowsMultiple()) {
|
||||
openValues = openValues.concat([value])
|
||||
} else {
|
||||
@@ -102,6 +102,7 @@ component Accordion {
|
||||
data-wrn-accordion
|
||||
data-variant="{variant}"
|
||||
data-indicator="{indicator}"
|
||||
data-indicator-position="{showIndicator ? indicatorPosition : 'none'}"
|
||||
data-multiple="{allowsMultiple() ? 'true' : 'false'}"
|
||||
class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--accordion wrn-next--accordion-{variant} {bordered ? 'wrn-next--accordion-bordered' : ''} {separated ? 'wrn-next--accordion-separated' : ''} {flush ? 'wrn-next--accordion-flush' : ''} {disabled ? 'wrn-next--disabled' : ''} {class}"
|
||||
>
|
||||
@@ -208,7 +209,7 @@ component Accordion {
|
||||
|
||||
style {
|
||||
.wrn-next--accordion {
|
||||
--wrn-accordion-accent: var(--wrn-component-color);
|
||||
--wrn-accordion-accent: var(--wrn-color-primary-text);
|
||||
display: grid;
|
||||
width: 100%;
|
||||
color: var(--wrn-color-text);
|
||||
@@ -234,7 +235,7 @@ component Accordion {
|
||||
color: var(--wrn-color-text);
|
||||
font: inherit;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 700;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -319,12 +320,16 @@ component Accordion {
|
||||
}
|
||||
|
||||
.wrn-next__accordion-content {
|
||||
padding: 0 0 1rem 1.75rem;
|
||||
padding: 0 0 1rem;
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.86rem;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.wrn-next--accordion[data-indicator-position="start"] .wrn-next__accordion-content {
|
||||
padding-inline-start: 1.75rem;
|
||||
}
|
||||
|
||||
.wrn-next__accordion-content > p {
|
||||
color: inherit;
|
||||
}
|
||||
@@ -369,6 +374,8 @@ component Accordion {
|
||||
|
||||
.wrn-next--accordion-separated {
|
||||
gap: 0.5rem;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.wrn-next--accordion-separated > .wrn-next__accordion-item {
|
||||
|
||||
@@ -73,8 +73,9 @@ component AdvancedSelect {
|
||||
state selectedValues = values
|
||||
|
||||
functions {
|
||||
shared function groupOptions(group) { return group.options || [] }
|
||||
shared function allOptions() {
|
||||
return [...groups.flatMap((group) => group.options || []), ...options]
|
||||
return groups.flatMap(groupOptions).concat(options)
|
||||
}
|
||||
|
||||
shared function searchableText(option) {
|
||||
@@ -95,7 +96,7 @@ component AdvancedSelect {
|
||||
}
|
||||
|
||||
shared function matchingOptions(list) {
|
||||
return list.filter((option) => matches(option))
|
||||
return list.filter(matches)
|
||||
}
|
||||
|
||||
shared function visibleOptions(list) {
|
||||
@@ -118,7 +119,7 @@ component AdvancedSelect {
|
||||
}
|
||||
|
||||
shared function selectedOptions() {
|
||||
return allOptions().filter((option) => isSelected(option))
|
||||
return allOptions().filter(isSelected)
|
||||
}
|
||||
|
||||
shared function selectedCount() {
|
||||
@@ -475,13 +476,14 @@ component AdvancedSelect {
|
||||
|
||||
.wrn-next__select-search .wrn-next__search-icon {
|
||||
inset-inline-start: 0.8em;
|
||||
left: auto;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wrn-next__select-search input {
|
||||
.wrn-next--advanced-select .wrn-next__select-search input {
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
font-size: 0.875rem;
|
||||
padding-inline-start: 2.4em;
|
||||
padding-inline-end: 0.75em;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ badge: string = ""
|
||||
state dismissed: boolean = false
|
||||
|
||||
view {
|
||||
<aside
|
||||
<div
|
||||
{...attrs}
|
||||
data-ui-component="AnnouncementBar"
|
||||
data-size='{size}'
|
||||
@@ -149,7 +149,7 @@ badge: string = ""
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
}
|
||||
|
||||
style {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Button from "./button.wrn"
|
||||
import Checkbox from "./Checkbox.wrn"
|
||||
import Input from "./Input.wrn"
|
||||
import Checkbox from "./checkbox.wrn"
|
||||
import Input from "./input.wrn"
|
||||
import PinInput from "./PinInput.wrn"
|
||||
|
||||
component AuthForm {
|
||||
|
||||
@@ -160,7 +160,7 @@ component AuthSplitLayout {
|
||||
.wrn-auth-split__message h1 {
|
||||
max-width: 14ch;
|
||||
margin: 0.65rem 0 0;
|
||||
font-size: clamp(2rem, 4vw, 3.75rem);
|
||||
font-size: clamp(1.75rem, 3vw, 2.5rem);
|
||||
font-weight: 650;
|
||||
letter-spacing: -0.045em;
|
||||
line-height: 1.08;
|
||||
@@ -221,7 +221,7 @@ component AuthSplitLayout {
|
||||
}
|
||||
|
||||
.wrn-auth-split__form-inner {
|
||||
width: min(100%, 30rem);
|
||||
width: min(100%, 24rem);
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
|
||||
@@ -63,7 +63,7 @@ component AvatarGroup {
|
||||
data-color="{item.color || color}"
|
||||
data-variant="{item.variant || variant}"
|
||||
tabindex="{showTooltips && (item.tooltip || item.name) ? '0' : '-1'}"
|
||||
aria-label="{item.name || item.alt || item.initials || 'Group member'}"
|
||||
aria-label="{item.tooltip || item.name || item.alt || item.initials || 'Group member'}"
|
||||
>
|
||||
<span
|
||||
class="wrn-next__avatar-group-avatar"
|
||||
@@ -241,6 +241,8 @@ component AvatarGroup {
|
||||
|
||||
.wrn-next__avatar-group-avatar,
|
||||
.wrn-next__avatar-group-overflow-button {
|
||||
white-space: nowrap;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -264,6 +266,9 @@ component AvatarGroup {
|
||||
}
|
||||
|
||||
.wrn-next__avatar-group-overflow-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface-2);
|
||||
|
||||
@@ -136,6 +136,7 @@ label: string = "Breadcrumb"
|
||||
--breadcrumb-text: var(--wrn-color-primary-text);
|
||||
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
color: var(--wrn-color-text-muted);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ items: unknown[] = []
|
||||
return item.value || item.label || String(index)
|
||||
}
|
||||
|
||||
client function selectItem(item, index) {
|
||||
client function selectItem(item, index, previousValue, nextValue) {
|
||||
previousValue = selectedValue
|
||||
nextValue = itemValue(item, index)
|
||||
|
||||
@@ -99,6 +99,26 @@ items: unknown[] = []
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.wrn-next--button-group > .wrn-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.45rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0 0.85rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
background: var(--wrn-color-surface);
|
||||
color: var(--wrn-color-text);
|
||||
font: inherit;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
.wrn-next--button-group > .wrn-btn:hover { background: var(--wrn-color-surface-2); }
|
||||
.wrn-next--button-group > .wrn-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.wrn-next--button-group > .wrn-btn .wrn-btn__icon { width: 1rem; height: 1rem; }
|
||||
.wrn-next--button-group[data-size="sm"] > .wrn-btn { min-height: 2rem; font-size: 0.8rem; }
|
||||
.wrn-next--button-group[data-orientation="vertical"] {
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -182,9 +202,9 @@ items: unknown[] = []
|
||||
}
|
||||
.wrn-next--button-group[data-selectable="true"] > .wrn-btn[data-selected="true"] {
|
||||
z-index: 1;
|
||||
border-color: var(--wrn-component-color);
|
||||
border-color: var(--wrn-color-primary-text);
|
||||
background: color-mix(in srgb, var(--wrn-component-color) 16%, var(--wrn-color-surface));
|
||||
color: var(--wrn-component-color);
|
||||
color: var(--wrn-color-primary-text);
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.wrn-next--button-group[data-responsive="true"] > :is(.wrn-btn, .wrn-action) {
|
||||
@@ -292,7 +312,7 @@ items: unknown[] = []
|
||||
}
|
||||
|
||||
.wrn-component :is(a, button, input, select, textarea):focus-visible {
|
||||
outline-color: var(--wrn-component-color);
|
||||
outline-color: var(--wrn-color-primary-text);
|
||||
}
|
||||
|
||||
.wrn-component p {
|
||||
|
||||
@@ -16,6 +16,8 @@ component Card {
|
||||
subtitleKey: string = ""
|
||||
description: string = ""
|
||||
descriptionKey: string = ""
|
||||
showHeader: boolean = true
|
||||
showFooter: boolean = true
|
||||
header: string = ""
|
||||
footer: string = ""
|
||||
imageSrc: string = ""
|
||||
@@ -170,8 +172,8 @@ component Card {
|
||||
{/if}
|
||||
|
||||
<div class="wrn-next__card-content">
|
||||
{#if header || title || subtitle || headerActions.length > 0 || dismissible}
|
||||
<header class="wrn-next__card-header">
|
||||
{#if showHeader}
|
||||
<header class="wrn-next__card-header"><slot name="header" />
|
||||
<div class="wrn-next__card-heading">
|
||||
{#if header}
|
||||
<p class="wrn-next__card-eyebrow">{header}</p>
|
||||
@@ -284,8 +286,8 @@ component Card {
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if footer || actionLabel}
|
||||
<footer class="wrn-next__card-footer">
|
||||
{#if showFooter}
|
||||
<footer class="wrn-next__card-footer"><div class="wrn-next__card-custom-footer"><slot name="footer" /></div>
|
||||
{#if footer}
|
||||
<span>{footer}</span>
|
||||
{/if}
|
||||
@@ -321,6 +323,8 @@ component Card {
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next__card-custom-footer:empty { display:none; }
|
||||
.wrn-next__card-header:not(:has(strong,h1,h2,h3,h4,p,button,[data-slot])), .wrn-next__card-footer:not(:has(> span, > a, > .wrn-next__card-custom-footer:not(:empty))) { display:none; }
|
||||
.wrn-next__card-media--overlay {
|
||||
aspect-ratio: 16 / 9;
|
||||
min-height: 18rem;
|
||||
@@ -340,7 +344,7 @@ component Card {
|
||||
|
||||
.wrn-next--card {
|
||||
--wrn-card-color: var(--wrn-component-color, var(--wrn-color-primary));
|
||||
--wrn-card-padding: 1.25rem;
|
||||
--wrn-card-padding: var(--wrn-space-panel, 1.25rem);
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: var(--wrn-color-text);
|
||||
@@ -354,10 +358,15 @@ component Card {
|
||||
.wrn-next--card[data-shadow="none"] > .wrn-next__card-panel { box-shadow: none; }
|
||||
.wrn-next--card[data-equal-height="true"], .wrn-next--card[data-equal-height="true"] > .wrn-next__card-panel { height: 100%; }
|
||||
.wrn-next--card[data-layout="horizontal"] .wrn-next__card-body { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 0.8rem; }
|
||||
.wrn-next__card-icon { display: grid; width: 2.35rem; height: 2.35rem; place-items: center; border-radius: 0.7rem; color: var(--wrn-color-primary); background: color-mix(in srgb, var(--wrn-color-primary) 12%, transparent); font-size: 1.15rem; }
|
||||
.wrn-next__card-icon { display: inline-block; width: 2rem; height: 2rem; color: var(--wrn-card-icon-color, var(--wrn-color-primary-text)); background-color: currentColor; }
|
||||
.wrn-next--card.wrn-component--color-secondary { --wrn-card-icon-color: var(--wrn-color-secondary-text); }
|
||||
.wrn-next--card.wrn-component--color-success { --wrn-card-icon-color: var(--wrn-color-success-text); }
|
||||
.wrn-next--card.wrn-component--color-warning { --wrn-card-icon-color: var(--wrn-color-warning-text); }
|
||||
.wrn-next--card.wrn-component--color-danger { --wrn-card-icon-color: var(--wrn-color-danger-text); }
|
||||
.wrn-next--card.wrn-component--color-info { --wrn-card-icon-color: var(--wrn-color-info-text); }
|
||||
|
||||
.wrn-next--card[data-size="lg"] {
|
||||
--wrn-card-padding: 1.75rem;
|
||||
--wrn-card-padding: 1.5rem;
|
||||
}
|
||||
|
||||
.wrn-next__card-panel {
|
||||
@@ -370,7 +379,7 @@ component Card {
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius-md);
|
||||
background: var(--wrn-color-surface);
|
||||
box-shadow: var(--wrn-shadow-1);
|
||||
box-shadow: none;
|
||||
transition:
|
||||
transform var(--wrn-motion-base) var(--wrn-ease-emphasized),
|
||||
border-color var(--wrn-motion-base) ease,
|
||||
@@ -384,8 +393,8 @@ component Card {
|
||||
|
||||
.wrn-next--card[data-hover="raise"] > .wrn-next__card-panel:hover {
|
||||
border-color: color-mix(in srgb, var(--wrn-card-color) 38%, var(--wrn-color-border));
|
||||
box-shadow: var(--wrn-shadow-3);
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--wrn-shadow-2);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.wrn-next__card-header,
|
||||
@@ -531,7 +540,7 @@ component Card {
|
||||
.wrn-next__card-subtitle {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@@ -626,9 +635,12 @@ component Card {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.wrn-next__card-group .wrn-next__card-content { padding: var(--wrn-card-padding, 1.25rem); display: grid; gap: 0.65rem; }
|
||||
.wrn-next__card-content h3 { margin: 0; font-size: 1rem; font-weight: 600; }
|
||||
.wrn-next__card-group {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--wrn-card-columns, 3), minmax(0, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wrn-next__card-group > .wrn-next__card-panel {
|
||||
|
||||
@@ -34,6 +34,7 @@ component Carousel {
|
||||
showCounter: boolean = false
|
||||
thumbnails: string = "none"
|
||||
ariaLabel: string = "Content carousel"
|
||||
framed: boolean = false
|
||||
variant: string = "default"
|
||||
class: string = ""
|
||||
}
|
||||
@@ -316,6 +317,7 @@ component Carousel {
|
||||
view {
|
||||
<section
|
||||
{...attrs}
|
||||
data-framed="{framed}"
|
||||
class="wrn-component wrn-next--carousel wrn-component--color-{color} wrn-component--size-{size} wrn-next--variant-{variant} {class}"
|
||||
data-rtl="{isRTL}"
|
||||
data-centered="{isCentered}"
|
||||
@@ -477,6 +479,22 @@ component Carousel {
|
||||
box-shadow: var(--wrn-shadow-1);
|
||||
}
|
||||
|
||||
.wrn-next--carousel[data-framed="false"] {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next__carousel-slide:has(> img)::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgb(0 0 0 / 0.4);
|
||||
pointer-events: none;
|
||||
}
|
||||
.wrn-next__carousel-slide:has(> img) .wrn-next__carousel-slide-content,
|
||||
.wrn-next__carousel-slide:has(> img) .wrn-next__carousel-slide-content p { color: white; }
|
||||
.wrn-next__carousel-header h3,
|
||||
.wrn-next__carousel-header p {
|
||||
margin: 0;
|
||||
@@ -515,6 +533,12 @@ component Carousel {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.wrn-next--carousel[data-framed="false"] .wrn-next__carousel-viewport {
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.wrn-next__carousel-viewport:focus-visible {
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--wrn-carousel-color) 30%, transparent);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ component Chart {
|
||||
title: string = "Chart"
|
||||
description: string = ""
|
||||
items: unknown[] = []
|
||||
data: unknown[] = []
|
||||
type: string = ""
|
||||
valueKey: string = "value"
|
||||
labelKey: string = "label"
|
||||
height: number = 240
|
||||
@@ -23,15 +25,17 @@ component Chart {
|
||||
state hiddenIndexes = []
|
||||
|
||||
functions {
|
||||
shared function chartData() { return data.length ? data : items }
|
||||
shared function linePoints() { return chartData().map(function (item, index) { return (barX(index) + barWidth() / 2) + "," + barY(item) }).join(" ") }
|
||||
shared function numericValue(item) { return Math.max(0, Number(item[valueKey]) || 0) }
|
||||
shared function maximumValue() {
|
||||
return Math.max(1, ...items.map(function (item) { return numericValue(item) }))
|
||||
return Math.max(1, ...chartData().map(function (item) { return numericValue(item) }))
|
||||
}
|
||||
shared function isHidden(index) { return hiddenIndexes.includes(index) }
|
||||
shared function barWidth() { return items.length ? Math.max(4, 80 / items.length) : 80 }
|
||||
shared function barX(index) { return 10 + index * (80 / Math.max(1, items.length)) }
|
||||
shared function barHeight(item) { return numericValue(item) / maximumValue() * 72 }
|
||||
shared function barY(item) { return 84 - barHeight(item) }
|
||||
shared function barWidth() { return chartData().length ? Math.max(4, 400 / chartData().length) : 400 }
|
||||
shared function barX(index) { return 50 + index * (500 / Math.max(1, chartData().length)) }
|
||||
shared function barHeight(item) { return numericValue(item) / maximumValue() * 160 }
|
||||
shared function barY(item) { return 200 - barHeight(item) }
|
||||
|
||||
client function selectPoint(item, index, sourceEvent) {
|
||||
output.dataPointClick({ item: item, index: index, sourceEvent: sourceEvent })
|
||||
@@ -58,25 +62,21 @@ component Chart {
|
||||
{#if description}<span>{description}</span>{/if}
|
||||
</figcaption>
|
||||
{/if}
|
||||
<svg class="wrn-chart__plot" viewBox="0 0 100 100" role="img" aria-label='{title}' style='height:{height}px'>
|
||||
<line x1="8" y1="84" x2="96" y2="84" class="wrn-chart__axis" />
|
||||
{#each items as item, index}
|
||||
<g data-hidden='{isHidden(index) ? "true" : "false"}'>
|
||||
<rect
|
||||
x='{barX(index)}' y='{barY(item)}' width='{barWidth()}' height='{barHeight(item)}'
|
||||
rx="1.5" class="wrn-chart__bar" role="button" tabindex="0"
|
||||
aria-label='{item[labelKey] + ": " + numericValue(item)}'
|
||||
@click='selectPoint(item, index, event)'
|
||||
@keydown='if (event.key === "Enter" || event.key === " ") { event.preventDefault(); selectPoint(item, index, event) }'
|
||||
/>
|
||||
{#if showValues}<text x='{barX(index) + barWidth() / 2}' y='{barY(item) - 3}' class="wrn-chart__value">{numericValue(item)}</text>{/if}
|
||||
<text x='{barX(index) + barWidth() / 2}' y="94" class="wrn-chart__label">{item[labelKey]}</text>
|
||||
</g>
|
||||
{/each}
|
||||
</svg>
|
||||
{#if (type || variant) === "line"}
|
||||
<svg class="wrn-chart__line" viewBox="0 0 600 240" role="img" aria-label="{title}" style="height:{height}px"><polyline points="{linePoints()}" fill="none" stroke="var(--wrn-color-primary)" stroke-width="3" /></svg>
|
||||
<div class="wrn-chart__point-labels">{#each chartData() as item, index}<button type="button" @click="selectPoint(item, index, event)">{item[labelKey]} · {numericValue(item)}</button>{/each}</div>
|
||||
{:else}
|
||||
<div class="wrn-chart__columns" style="height:{height}px" role="group" aria-label="{title}">
|
||||
{#each chartData() as item, index}<button type="button" class="wrn-chart__column" data-hidden="{hiddenIndexes.includes(index)}" aria-label="{item[labelKey] + ': ' + numericValue(item)}" @click="selectPoint(item, index, event)">
|
||||
{#if showValues}<span>{numericValue(item)}</span>{/if}
|
||||
<svg viewBox="0 0 60 160" preserveAspectRatio="none" aria-hidden="true" style="height:{numericValue(item) / maximumValue() * Math.max(60, height - 60)}px"><rect x="0" y="0" width="60" height="160" rx="3" fill="var(--wrn-color-primary)" /></svg>
|
||||
<small>{item[labelKey]}</small>
|
||||
</button>{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if showLegend}
|
||||
<div class="wrn-chart__legend" aria-label="Chart legend">
|
||||
{#each items as item, index}
|
||||
{#each chartData() as item, index}
|
||||
<button type="button" aria-pressed='{isHidden(index) ? "false" : "true"}' @click='toggleLegend(item, index, event)'>
|
||||
<span aria-hidden="true"></span>{item[labelKey]}
|
||||
</button>
|
||||
@@ -88,6 +88,15 @@ component Chart {
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-chart__columns { display:flex; align-items:flex-end; gap:clamp(.5rem,2vw,1.5rem); padding:.5rem; border-bottom:1px solid var(--wrn-color-border); }
|
||||
.wrn-chart__column { display:flex; flex:1; min-width:0; flex-direction:column; align-items:center; gap:.6rem; padding:0; border:0; background:transparent; color:var(--wrn-color-text); font:inherit; font-size:.8rem; cursor:pointer; }
|
||||
.wrn-chart__column svg { width:100%; max-width:5rem; min-height:1px; }
|
||||
.wrn-chart__column small { max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--wrn-color-muted); }
|
||||
.wrn-chart__column[data-hidden="true"] { opacity:.2; }
|
||||
.wrn-chart__line { width:100%; display:block; }
|
||||
.wrn-chart__point-labels { display:flex; justify-content:space-around; gap:.5rem; flex-wrap:wrap; }
|
||||
.wrn-chart__point-labels button { border:0; background:transparent; color:var(--wrn-color-muted); font:inherit; font-size:.8rem; cursor:pointer; }
|
||||
|
||||
.wrn-chart { display: grid; gap: 1rem; min-width: 0; margin: 0; padding: 1rem; border: 1px solid var(--wrn-color-border); border-radius: var(--wrn-radius); color: var(--wrn-color-text); background: var(--wrn-color-surface); box-shadow: var(--wrn-shadow-1); }
|
||||
.wrn-chart__header { display: grid; gap: 0.2rem; }
|
||||
.wrn-chart__header > span { color: var(--wrn-color-muted); font-size: 0.8rem; }
|
||||
@@ -97,7 +106,7 @@ component Chart {
|
||||
.wrn-chart__bar:hover { opacity: 0.82; transform: scaleY(1.02); }
|
||||
.wrn-chart__bar:focus-visible { outline: 1.5px solid var(--wrn-color-focus); outline-offset: 1px; }
|
||||
.wrn-chart__plot g[data-hidden="true"] { opacity: 0.18; pointer-events: none; }
|
||||
.wrn-chart__value, .wrn-chart__label { fill: var(--wrn-color-text); font-size: 3.5px; text-anchor: middle; }
|
||||
.wrn-chart__value, .wrn-chart__label { fill: var(--wrn-color-text); font-size: 11px; text-anchor: middle; }
|
||||
.wrn-chart__label { fill: var(--wrn-color-muted); }
|
||||
.wrn-chart__legend { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.wrn-chart__legend button { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.3rem 0.5rem; border: 1px solid var(--wrn-color-border); border-radius: 999px; color: var(--wrn-color-text); background: transparent; font: inherit; font-size: 0.75rem; cursor: pointer; }
|
||||
|
||||
@@ -12,6 +12,7 @@ component Clipboard {
|
||||
errorLabel: string = "Copy failed"
|
||||
title: string = "Clipboard"
|
||||
description: string = ""
|
||||
iconOnly: boolean = false
|
||||
code: boolean = true
|
||||
size: string = "default"
|
||||
color: string = "primary"
|
||||
@@ -73,7 +74,7 @@ component Clipboard {
|
||||
>
|
||||
<span class="icon-[lucide--copy] wrn-clipboard__icon" data-show='status !== "success"' aria-hidden="true"></span>
|
||||
<span class="icon-[lucide--check] wrn-clipboard__icon" data-show='status === "success"' aria-hidden="true"></span>
|
||||
<span>{status === "success" ? copiedLabel : status === "error" ? errorLabel : label}</span>
|
||||
{#if !iconOnly}<span>{status === "success" ? copiedLabel : status === "error" ? errorLabel : label}</span>{/if}
|
||||
</button>
|
||||
</div>
|
||||
<slot />
|
||||
|
||||
@@ -151,10 +151,10 @@ component ColorPicker {
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -168,9 +168,9 @@ component ColorPicker {
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -212,7 +212,7 @@ component ColorPicker {
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -226,10 +226,10 @@ component ColorPicker {
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -337,7 +337,7 @@ component ColorPicker {
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -346,7 +346,7 @@ component ColorPicker {
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -495,7 +495,7 @@ component ColorPicker {
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -62,8 +62,9 @@ component ComboBox {
|
||||
state activeIndex: number = -1
|
||||
|
||||
functions {
|
||||
shared function groupOptions(group) { return group.options || [] }
|
||||
shared function allOptions() {
|
||||
return [...groups.flatMap((group) => group.options || []), ...options]
|
||||
return groups.flatMap(groupOptions).concat(options)
|
||||
}
|
||||
|
||||
shared function searchableText(option) {
|
||||
@@ -84,7 +85,7 @@ component ComboBox {
|
||||
}
|
||||
|
||||
shared function matchingOptions(list) {
|
||||
return list.filter((option) => matches(option))
|
||||
return list.filter(matches)
|
||||
}
|
||||
|
||||
shared function visibleOptions(list) {
|
||||
@@ -103,7 +104,7 @@ component ComboBox {
|
||||
}
|
||||
|
||||
shared function selectedOptions() {
|
||||
return allOptions().filter((option) => isSelected(option))
|
||||
return allOptions().filter(isSelected)
|
||||
}
|
||||
|
||||
shared function selectedText() {
|
||||
@@ -312,8 +313,7 @@ component ComboBox {
|
||||
role="listbox"
|
||||
>
|
||||
{#each groups as group}
|
||||
{#if visibleOptions(group.options || []).length}
|
||||
<div class="wrn-next__option-group" role="group" aria-label="{group.label}">
|
||||
<div class="wrn-next__option-group" role="group" aria-label="{group.label}" data-show="visibleOptions(group.options || []).length > 0">
|
||||
<div class="wrn-next__group-label">{group.label}</div>
|
||||
{#each group.options || [] as option}
|
||||
<button
|
||||
@@ -336,7 +336,6 @@ component ComboBox {
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
{#each options as option}
|
||||
|
||||
@@ -7,7 +7,7 @@ component Confetti {
|
||||
props {
|
||||
label: string = "Celebrate"
|
||||
duration: number = 1200
|
||||
count: number = 24
|
||||
count: number = 80
|
||||
autoStart: boolean = false
|
||||
disabled: boolean = false
|
||||
size: string = "default"
|
||||
@@ -18,9 +18,45 @@ component Confetti {
|
||||
state running = false
|
||||
|
||||
functions {
|
||||
shared function pieces() { return Array.from({ length: Math.max(1, Math.min(60, count)) }) }
|
||||
shared function pieces() { return Array.from({ length: Math.max(1, Math.min(200, count)) }) }
|
||||
shared function pieceStyle(index) {
|
||||
return "--wrn-confetti-index:" + index + ";--wrn-confetti-x:" + ((index * 37) % 100) + ";--wrn-confetti-delay:" + ((index * 29) % 240) + "ms;"
|
||||
return "--wrn-confetti-index:" + index + ";--wrn-confetti-x:" + ((index * 37) % 100) + ";--wrn-confetti-delay:" + 0 + "ms;"
|
||||
}
|
||||
client function animateFrame(canvas, particles, started) {
|
||||
var context = canvas.getContext("2d")
|
||||
var progress = (Date.now() - started) / Math.max(1, duration)
|
||||
context.clearRect(0, 0, 720, 420)
|
||||
if (progress >= 1 || !canvas.isConnected) { return }
|
||||
particles.forEach(function (piece) {
|
||||
piece.vx = piece.vx * 0.99
|
||||
piece.vy = piece.vy + 0.19
|
||||
piece.x = piece.x + piece.vx
|
||||
piece.y = piece.y + piece.vy
|
||||
piece.rotation = piece.rotation + piece.spin
|
||||
context.save()
|
||||
context.translate(piece.x, piece.y)
|
||||
context.rotate(piece.rotation)
|
||||
context.globalAlpha = Math.min(1, (1 - progress) * 4)
|
||||
context.fillStyle = piece.color
|
||||
context.fillRect(-3, -4, 6, 8 * Math.cos(piece.rotation))
|
||||
context.restore()
|
||||
})
|
||||
setTimeout(animateFrame, 16, canvas, particles, started)
|
||||
}
|
||||
client function animateBurst(sourceEvent) {
|
||||
var root = sourceEvent.currentTarget.closest(".wrn-confetti")
|
||||
var canvas = root.querySelector("canvas")
|
||||
if (!canvas || window.matchMedia("(prefers-reduced-motion: reduce)").matches) { return }
|
||||
var context = canvas.getContext("2d")
|
||||
if (!context) { return }
|
||||
canvas.width = 720
|
||||
canvas.height = 420
|
||||
var particles = Array.from({length:Math.min(200, Math.max(1, count))}, function (_, index) {
|
||||
var angle = (-155 + Math.random() * 130) * Math.PI / 180
|
||||
var speed = 5 + Math.random() * 9
|
||||
return {x:360,y:273,vx:Math.cos(angle) * speed,vy:Math.sin(angle) * speed,rotation:Math.random() * 6,spin:(Math.random() - 0.5) * 0.3,color:["#8b5cf6","#14b8a6","#f59e0b","#f472b6","#60a5fa"][index % 5]}
|
||||
})
|
||||
animateFrame(canvas, particles, Date.now())
|
||||
}
|
||||
client function finish(sourceEvent) {
|
||||
running = false
|
||||
@@ -31,6 +67,7 @@ component Confetti {
|
||||
return
|
||||
}
|
||||
running = true
|
||||
if (sourceEvent) { animateBurst(sourceEvent) }
|
||||
output.start({ sourceEvent: sourceEvent, duration: duration })
|
||||
setTimeout(finish, duration, sourceEvent)
|
||||
}
|
||||
@@ -41,11 +78,11 @@ component Confetti {
|
||||
}
|
||||
|
||||
view {
|
||||
<div {...attrs} data-ui-component="Confetti" data-running='{running ? "true" : "false"}' class='wrn-confetti {class}' style='--wrn-confetti-duration:{duration}ms'>
|
||||
<div {...attrs} data-ui-component="Confetti" data-autostart="{autoStart}" data-running='{running ? "true" : "false"}' class='wrn-confetti {class}' style='--wrn-confetti-duration:{duration}ms'>
|
||||
<button type="button" class="wrn-confetti__trigger" disabled='{disabled}' @click='start(event)'>
|
||||
<span class="icon-[lucide--party-popper]" aria-hidden="true"></span><span>{label}</span>
|
||||
</button>
|
||||
<div class="wrn-confetti__burst" aria-hidden="true">
|
||||
<canvas class="wrn-confetti__canvas" aria-hidden="true"></canvas><div class="wrn-confetti__burst" aria-hidden="true">
|
||||
{#each pieces() as piece, index}<i style='{pieceStyle(index)}'></i>{/each}
|
||||
</div>
|
||||
<slot />
|
||||
@@ -53,17 +90,21 @@ component Confetti {
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-confetti__canvas { position:absolute; width:720px; height:420px; left:50%; top:50%; transform:translate(-50%,-65%); pointer-events:none; z-index:5; }
|
||||
.wrn-confetti__burst { display:none; }
|
||||
.wrn-confetti[data-autostart="true"] .wrn-confetti__burst { display:block; }
|
||||
.wrn-confetti { position: relative; display: inline-flex; }
|
||||
.wrn-confetti__trigger { display: inline-flex; min-height: 2.5rem; align-items: center; gap: 0.5rem; padding: 0.55rem 0.85rem; border: 1px solid var(--wrn-color-primary); border-radius: var(--wrn-radius); color: var(--wrn-color-on-primary); background: var(--wrn-color-primary); font: inherit; font-weight: 700; cursor: pointer; }
|
||||
.wrn-confetti__trigger > span:first-child { width: 1rem; height: 1rem; }
|
||||
.wrn-confetti__trigger:focus-visible { outline: 2px solid var(--wrn-color-focus); outline-offset: 2px; }
|
||||
.wrn-confetti__trigger:disabled { cursor: not-allowed; opacity: 0.55; }
|
||||
.wrn-confetti__burst { position: absolute; inset: 50% 0 auto; height: 0; pointer-events: none; }
|
||||
.wrn-confetti__burst > i { position: absolute; left: calc(var(--wrn-confetti-x) * 1%); width: 0.45rem; height: 0.7rem; border-radius: 0.1rem; opacity: 0; background: hsl(calc(var(--wrn-confetti-index) * 47deg) 80% 55%); transform: translate(-50%, 0) rotate(calc(var(--wrn-confetti-index) * 23deg)); }
|
||||
.wrn-confetti[data-running="true"] .wrn-confetti__burst > i { animation: wrn-confetti-burst var(--wrn-confetti-duration) cubic-bezier(0.2, 0.7, 0.2, 1) var(--wrn-confetti-delay) both; }
|
||||
.wrn-confetti__burst { position: absolute; inset: 50% 0 auto; z-index:10; height: 0; pointer-events: none; }
|
||||
.wrn-confetti__burst > i { position: absolute; left:50%; width: 0.45rem; height: 0.7rem; border-radius: 0.1rem; opacity: 0; background: hsl(calc(var(--wrn-confetti-index) * 47deg) 80% 55%); transform: translate(-50%, 0) rotate(calc(var(--wrn-confetti-index) * 23deg)); }
|
||||
.wrn-confetti[data-running="true"] .wrn-confetti__burst > i { animation: wrn-confetti-burst var(--wrn-confetti-duration) linear var(--wrn-confetti-delay) both; }
|
||||
@keyframes wrn-confetti-burst {
|
||||
0% { opacity: 1; transform: translate(-50%, 0) rotate(0); }
|
||||
100% { opacity: 0; transform: translate(calc(-50% + (var(--wrn-confetti-x) - 50) * 0.9px), 9rem) rotate(540deg); }
|
||||
30% { opacity: 1; transform: translate(calc(-50% + (var(--wrn-confetti-x) - 50) * 6px), calc(-5rem - var(--wrn-confetti-x) * 1.2px)) rotate(180deg); }
|
||||
100% { opacity: 0; transform: translate(calc(-50% + (var(--wrn-confetti-x) - 50) * 9px), 14rem) rotate(540deg); }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.wrn-confetti[data-running="true"] .wrn-confetti__burst > i { animation-duration: 1ms; animation-delay: 0ms; }
|
||||
|
||||
@@ -37,6 +37,12 @@ component ContextMenu {
|
||||
return open || visible
|
||||
}
|
||||
|
||||
client function handleContext(sourceEvent) {
|
||||
if (trigger === "contextmenu" || trigger === "both") { sourceEvent.preventDefault(); showMenu(sourceEvent) }
|
||||
}
|
||||
client function handleClick(sourceEvent) {
|
||||
if (trigger === "click" || trigger === "both") { toggleMenu(sourceEvent) }
|
||||
}
|
||||
client function showMenu(sourceEvent) {
|
||||
if (disabled) {
|
||||
return
|
||||
@@ -146,8 +152,8 @@ component ContextMenu {
|
||||
tabindex='{disabled ? "-1" : "0"}'
|
||||
aria-haspopup="menu"
|
||||
aria-expanded='{open || visible ? "true" : "false"}'
|
||||
@contextmenu='if (trigger === "contextmenu" || trigger === "both") { showMenu(event) }'
|
||||
@click='if (trigger === "click" || trigger === "both") { toggleMenu(event) }'
|
||||
@contextmenu='handleContext(event)'
|
||||
@click='handleClick(event)'
|
||||
@keydown='if (event.key === "Enter" || event.key === " ") { event.preventDefault(); toggleMenu(event) }'
|
||||
>
|
||||
<slot name="trigger"></slot>
|
||||
@@ -296,7 +302,7 @@ component ContextMenu {
|
||||
}
|
||||
|
||||
.wrn-context-menu__trigger:focus-visible {
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 2px solid var(--wrn-color-focus);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
@@ -325,7 +331,7 @@ component ContextMenu {
|
||||
linear-gradient(145deg, color-mix(in srgb, var(--context-accent) 5%, transparent), transparent 58%),
|
||||
color-mix(in srgb, var(--wrn-color-surface-raised) 96%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--context-accent) 18%, var(--wrn-color-border));
|
||||
border-radius: 1rem;
|
||||
border-radius: var(--wrn-radius-md);
|
||||
box-shadow:
|
||||
0 1px 0 color-mix(in srgb, white 5%, transparent) inset,
|
||||
0 24px 64px color-mix(in srgb, black 24%, transparent);
|
||||
|
||||
@@ -13,96 +13,22 @@ component DataMap {
|
||||
variant: string = "default"
|
||||
class: string = ""
|
||||
}
|
||||
state selectedLabel: string = ""
|
||||
functions {
|
||||
client function choose(item) { selectedLabel = item.label; output.select({ value: item.value, item: item }); output.change({ value: item.value, item: item }) }
|
||||
shared function shade(item) { return Math.max(6, Math.min(35, (Number(item.value) || 0) / 3)) + "%" }
|
||||
}
|
||||
view {
|
||||
<section class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--data-map wrn-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wrn-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
</section>
|
||||
<section {...attrs} class="wrn-data-map {class}">{#if title}<strong>{title}</strong>{/if}{#if description}<p>{description}</p>{/if}<div class="wrn-data-map__grid" role="group" aria-label="{title}">{#each items as item}<button type="button" aria-pressed="{selectedLabel === item.label}" style="--heat:{shade(item)}" @click="choose(item)"><strong>{item.label}</strong><span>{item.value}</span></button>{/each}</div><small>Lower activity <span class="wrn-data-map__legend"></span> Higher activity</small><slot /></section>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next--data-map {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius);
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface);
|
||||
}
|
||||
.wrn-next--data-map > p { margin: 0; color: var(--wrn-color-muted); }
|
||||
.wrn-next--data-map > .wrn-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.wrn-next--data-map > .wrn-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wrn-radius-sm); background: var(--wrn-color-surface-2); }
|
||||
|
||||
/* 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;
|
||||
}
|
||||
.wrn-data-map { display:grid; gap:.85rem; color:var(--wrn-color-text); }
|
||||
.wrn-data-map p { margin:0; color:var(--wrn-color-muted); font-size:.875rem; }
|
||||
.wrn-data-map__grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(6rem,1fr)); gap:.4rem; }
|
||||
.wrn-data-map button { display:grid; gap:.35rem; padding:1rem .65rem; border:1px solid var(--wrn-color-border); border-radius:6px; background:color-mix(in srgb,var(--wrn-color-primary) var(--heat),var(--wrn-color-surface)); color:var(--wrn-color-text); font:inherit; font-size:.8rem; cursor:pointer; }
|
||||
.wrn-data-map button[aria-pressed="true"] { outline:2px solid var(--wrn-color-primary-text); outline-offset:2px; }
|
||||
.wrn-data-map small { display:flex; align-items:center; gap:.5rem; color:var(--wrn-color-muted); }
|
||||
.wrn-data-map__legend { display:inline-block; width:4rem; height:.5rem; background:linear-gradient(90deg,var(--wrn-color-primary-soft),var(--wrn-color-primary)); border-radius:4px; }
|
||||
}
|
||||
}
|
||||
@@ -964,6 +964,7 @@ component DataTable {
|
||||
size="sm"
|
||||
placement="top-end"
|
||||
label=""
|
||||
value='{perPage}'
|
||||
items='{pageSizeItems()}'
|
||||
@select='pickPageSize(payload)'
|
||||
>
|
||||
@@ -1053,7 +1054,7 @@ component DataTable {
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius-md);
|
||||
background: var(--wrn-color-surface);
|
||||
box-shadow: var(--wrn-shadow-1);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.wrn-table {
|
||||
@@ -1174,7 +1175,7 @@ component DataTable {
|
||||
color: var(--wrn-color-text-muted);
|
||||
background: var(--wrn-color-surface-soft);
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.7rem;
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
}
|
||||
|
||||
.wrn-table__search input {
|
||||
@@ -1209,7 +1210,7 @@ component DataTable {
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.9rem;
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
}
|
||||
|
||||
.wrn-table[data-bordered="false"] .wrn-table__scroll {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import TimePicker from "./TimePicker.wrn"
|
||||
|
||||
component DatePicker {
|
||||
outputs {
|
||||
input(payload: { sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[])
|
||||
@@ -20,9 +22,9 @@ size: string = "default"
|
||||
type: string = "date"
|
||||
locale: string = "en-US"
|
||||
firstDayOfWeek: number = 0
|
||||
months = [{ label: "Jan", value: "01" }, { label: "Feb", value: "02" }, { label: "Mar", value: "03" }, { label: "Apr", value: "04" }, { label: "May", value: "05" }, { label: "Jun", value: "06" }, { label: "Jul", value: "07" }, { label: "Aug", value: "08" }, { label: "Sep", value: "09" }, { label: "Oct", value: "10" }, { label: "Nov", value: "11" }, { label: "Dec", value: "12" }]
|
||||
days = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
|
||||
years = [2024, 2025, 2026, 2027, 2028, 2029, 2030]
|
||||
months: { label: string; value: string }[] = [{ label: "Jan", value: "01" }, { label: "Feb", value: "02" }, { label: "Mar", value: "03" }, { label: "Apr", value: "04" }, { label: "May", value: "05" }, { label: "Jun", value: "06" }, { label: "Jul", value: "07" }, { label: "Aug", value: "08" }, { label: "Sep", value: "09" }, { label: "Oct", value: "10" }, { label: "Nov", value: "11" }, { label: "Dec", value: "12" }]
|
||||
days: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
|
||||
years: number[] = [2024, 2025, 2026, 2027, 2028, 2029, 2030]
|
||||
min: string = ""
|
||||
max: string = ""
|
||||
step: string = ""
|
||||
@@ -37,30 +39,117 @@ size: string = "default"
|
||||
class: string = ""
|
||||
}
|
||||
state currentValue = value
|
||||
state selectedYear = value ? value.split("-")[0] : ""
|
||||
state selectedMonth = value ? value.split("-")[1] : ""
|
||||
state selectedDay = value ? value.split("-")[2] : ""
|
||||
state selectedYear = value ? value.split("-")[0] : String(new Date().getFullYear())
|
||||
state selectedMonth = value ? value.split("-")[1] : String(new Date().getMonth() + 1).padStart(2, "0")
|
||||
state selectedDay = value ? value.slice(8, 10) : ""
|
||||
state selectedTime = value.includes("T") ? value.split("T")[1].slice(0, 5) : "09:00"
|
||||
state expanded: boolean = false
|
||||
functions {
|
||||
client function openCalendar(sourceEvent) { expanded = true; output.open({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function updateDate(part, nextValue, sourceEvent, nextDate, detail) { if (part === "year") { selectedYear = String(nextValue) } if (part === "month") { selectedMonth = String(nextValue).padStart(2, "0") } if (part === "day") { selectedDay = String(nextValue).padStart(2, "0") } if (!selectedYear || !selectedMonth || !selectedDay) { return } nextDate = selectedYear + "-" + selectedMonth + "-" + selectedDay; if ((min && nextDate < min) || (max && nextDate > max)) { return } currentValue = nextDate; detail = { value: currentValue, year: selectedYear, month: selectedMonth, day: selectedDay, name: name, sourceEvent: sourceEvent }; output.input(detail); output.change(detail) }
|
||||
client function finishDate(sourceEvent) { if (!currentValue) { return } expanded = false; output.close({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function selectDay(sourceEvent, root, input, nextDate, trigger, detail) { root = sourceEvent.currentTarget.closest(".wrn-next--date-picker"); input = root.querySelector(".wrn-next__picker-value"); nextDate = input.getAttribute("value").slice(0, 5) + root.querySelector("select").getAttribute("value") + "-" + sourceEvent.currentTarget.dataset.value; currentValue = nextDate; input.setAttribute("value", nextDate); trigger = root.querySelector(".wrn-next__date-trigger span"); if (trigger) { trigger.replaceChildren(nextDate) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: nextDate, name: name, sourceEvent: sourceEvent }; output.input(detail); output.change(detail) }
|
||||
client function clearDate(sourceEvent, detail) { if (disabled || readonly) { return } currentValue = ""; detail = { value: currentValue, name: name, sourceEvent: sourceEvent }; output.input(detail); output.change(detail) }
|
||||
client function updateTime(sourceEvent) {
|
||||
selectedTime = sourceEvent.currentTarget.value
|
||||
currentValue = (currentValue ? currentValue.slice(0, 10) : selectedYear + "-" + selectedMonth + "-01") + "T" + selectedTime
|
||||
output.input({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
output.change({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
}
|
||||
|
||||
shared function calendarYears() {
|
||||
if (years.includes(Number(selectedYear))) { return years }
|
||||
return years.concat(Number(selectedYear))
|
||||
}
|
||||
shared function weekdayName(index, first) {
|
||||
first = ((firstDayOfWeek % 7) + 7) % 7
|
||||
return Intl.DateTimeFormat(locale, { weekday: "short", timeZone: "UTC" }).format(Date.UTC(2024, 0, 7 + first + index))
|
||||
}
|
||||
shared function weekdays() { return [0, 1, 2, 3, 4, 5, 6].map(weekdayName) }
|
||||
shared function validDay(day, year, leap, count) {
|
||||
year = Number(selectedYear)
|
||||
leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)
|
||||
count = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][Number(selectedMonth) - 1]
|
||||
return Number(day) >= 1 && Number(day) <= count
|
||||
}
|
||||
shared function dayView(day, year, month, first, offset, date, today) {
|
||||
year = Number(selectedYear)
|
||||
month = Number(selectedMonth)
|
||||
first = ((firstDayOfWeek % 7) + 7) % 7
|
||||
offset = ((Math.floor(Date.UTC(year, month - 1, 1) / 86400000) + 4) % 7 - first + 7) % 7
|
||||
date = selectedYear + "-" + selectedMonth + "-" + String(day).padStart(2, "0")
|
||||
today = Intl.DateTimeFormat("en-CA", { year: "numeric", month: "2-digit", day: "2-digit" }).format(Date.now())
|
||||
return { day: day, value: date, column: ((offset + Number(day) - 1) % 7) + 1, disabled: disabled || readonly || !!(min && date < min.slice(0, 10)) || !!(max && date > max.slice(0, 10)), today: date === today, label: Intl.DateTimeFormat(locale, { dateStyle: "full", timeZone: "UTC" }).format(Date.UTC(year, month - 1, Number(day))) }
|
||||
}
|
||||
shared function calendarDays() { return days.filter(validDay).map(dayView) }
|
||||
client function openCalendar(sourceEvent) {
|
||||
if (disabled || readonly) { return }
|
||||
expanded = !expanded
|
||||
syncCalendarSelectors(sourceEvent)
|
||||
if (expanded) { output.open({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
else { output.close({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
}
|
||||
client function updateDate(part, nextValue, sourceEvent) {
|
||||
if (disabled || readonly) { return }
|
||||
if (part === "year") { selectedYear = String(nextValue) }
|
||||
if (part === "month") { selectedMonth = String(nextValue).padStart(2, "0") }
|
||||
syncCalendarSelectors(sourceEvent)
|
||||
}
|
||||
client function syncCalendarSelectors(sourceEvent) {
|
||||
var root = sourceEvent.currentTarget.closest(".wrn-next--date-picker")
|
||||
setTimeout(applyCalendarSelectors, 0, root)
|
||||
}
|
||||
client function applyCalendarSelectors(root) {
|
||||
var selectors = root.querySelectorAll(".wrn-next__date-selectors select")
|
||||
selectors[0].value = selectedMonth
|
||||
selectors[1].value = selectedYear
|
||||
}
|
||||
client function finishDate(sourceEvent) {
|
||||
var root = sourceEvent.currentTarget.closest(".wrn-next--date-picker")
|
||||
root.querySelector(".wrn-next__date-trigger").focus()
|
||||
expanded = false
|
||||
output.close({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
}
|
||||
client function selectDay(sourceEvent) {
|
||||
if (disabled || readonly || sourceEvent.currentTarget.disabled) { return }
|
||||
var nextDate = sourceEvent.currentTarget.dataset.value
|
||||
if ((min && nextDate < min.slice(0, 10)) || (max && nextDate > max.slice(0, 10))) { return }
|
||||
currentValue = nextDate + (type === "datetime-local" ? "T" + selectedTime : "")
|
||||
selectedDay = nextDate.slice(8)
|
||||
syncCalendarSelectors(sourceEvent)
|
||||
var detail = { value: currentValue, year: selectedYear, month: selectedMonth, day: selectedDay, name: name, sourceEvent: sourceEvent }
|
||||
output.input(detail)
|
||||
output.change(detail)
|
||||
}
|
||||
client function calendarKeydown(sourceEvent) {
|
||||
if (sourceEvent.key === "Escape" && expanded) { sourceEvent.preventDefault(); finishDate(sourceEvent); return }
|
||||
var keys = { ArrowRight: 1, ArrowLeft: -1, ArrowDown: 7, ArrowUp: -7 }
|
||||
if (!keys[sourceEvent.key] || !sourceEvent.target.closest(".wrn-next__calendar-grid")) { return }
|
||||
sourceEvent.preventDefault()
|
||||
var root = sourceEvent.currentTarget
|
||||
var buttons = Array.from(root.querySelectorAll(".wrn-next__calendar-grid button"))
|
||||
var index = buttons.indexOf(sourceEvent.target) + keys[sourceEvent.key]
|
||||
while (index >= 0 && index < buttons.length && buttons[index].disabled) { index += keys[sourceEvent.key] > 0 ? 1 : -1 }
|
||||
if (buttons[index]) { buttons[index].focus() }
|
||||
}
|
||||
client function clearDate(sourceEvent) {
|
||||
if (disabled || readonly) { return }
|
||||
currentValue = ""
|
||||
selectedDay = ""
|
||||
var detail = { value: currentValue, name: name, sourceEvent: sourceEvent }
|
||||
output.input(detail)
|
||||
output.change(detail)
|
||||
}
|
||||
client function handleFocus(sourceEvent) { output.focus({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function handleBlur(sourceEvent) { output.blur({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function handleInvalid(sourceEvent) { output.invalid({ name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
|
||||
}
|
||||
view {
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--date-picker {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}" data-expanded="{expanded}">
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--date-picker {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}" data-expanded="{expanded}" @keydown="calendarKeydown(event)">
|
||||
<div class="wrn-next__field-heading"><label for="{id || name}">{label}</label>{#if cornerHint}<span class="wrn-next__field-hint">{cornerHint}</span>{/if}</div>
|
||||
<div class="wrn-next__picker-control"><input id="{id || name}" class="wrn-next__sr-only wrn-next__picker-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" /><button type="button" class="wrn-next__date-trigger" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openCalendar(event)" @focus="handleFocus(event)" @blur="handleBlur(event)"><span>{currentValue || placeholder || "Select date"}</span><i class="icon-[lucide--calendar-days]" aria-hidden="true"></i></button>{#if currentValue && !readonly && !disabled}<button type="button" class="wrn-next__picker-clear" aria-label="Clear date" @click="clearDate(event)">×</button>{/if}</div>
|
||||
<div class="wrn-next__calendar" role="dialog" aria-label="{label}"><div class="wrn-next__date-selectors"><label>Month<select value="{selectedMonth}" @change="updateDate('month', event.currentTarget.value, event)">{#each months as month}<option value="{month.value}" selected="{month.value === selectedMonth}">{month.label}</option>{/each}</select></label><label>Year<select value="{selectedYear}" @change="updateDate('year', event.currentTarget.value, event)">{#each years as year}<option value="{year}" selected="{String(year) === selectedYear}">{year}</option>{/each}</select></label></div><div class="wrn-next__calendar-grid">{#each days as day}<button type="button" data-value="{String(day).padStart(2, '0')}" aria-pressed="{String(day).padStart(2, '0') === selectedDay}" @click="selectDay(event)">{day}</button>{/each}</div><button type="button" class="wrn-next__date-done" disabled="{!currentValue}" @click="finishDate(event)">Done</button></div>
|
||||
<div class="wrn-next__picker-control"><input id="{id || name}" class="wrn-next__sr-only wrn-next__picker-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" /><button type="button" class="wrn-next__date-trigger" aria-label="{label}" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openCalendar(event)" @focus="handleFocus(event)" @blur="handleBlur(event)"><span>{currentValue || placeholder || "Select date"}</span><i class="icon-[lucide--calendar-days]" aria-hidden="true"></i></button>{#if currentValue && !readonly && !disabled}<button type="button" class="wrn-next__picker-clear" aria-label="Clear date" @click="clearDate(event)">×</button>{/if}</div>
|
||||
<button type="button" class="wrn-picker-dismiss" aria-label="Close calendar" data-show="expanded" @click="finishDate(event)"></button><div data-show="expanded" class="wrn-next__calendar" role="dialog" aria-label="{label}"><div class="wrn-next__date-selectors"><label>Month<select value="{selectedMonth}" @change="updateDate('month', event.currentTarget.value, event)">{#each months as month}<option value="{month.value}" selected="{month.value === selectedMonth}">{month.label}</option>{/each}</select></label><label>Year<select value="{selectedYear}" @change="updateDate('year', event.currentTarget.value, event)">{#each calendarYears() as calendarYear}<option value="{calendarYear}" selected="{String(calendarYear) === selectedYear}" data-text="calendarYear"></option>{/each}</select></label></div><div class="wrn-next__calendar-weekdays" aria-hidden="true">{#each weekdays() as weekday}<span>{weekday}</span>{/each}</div><div class="wrn-next__calendar-grid">{#each calendarDays() as day}<button type="button" data-value="{day.value}" data-today="{day.today}" style="grid-column: {day.column}" disabled="{day.disabled}" aria-label="{day.label}" aria-pressed="{day.value === currentValue.slice(0, 10)}" @click="selectDay(event)">{day.day}</button>{/each}</div>{#if type === "datetime-local"}<TimePicker label="Time" value="{selectedTime}" @change="selectedTime = payload.value; currentValue = (currentValue ? currentValue.slice(0, 10) : selectedYear + '-' + selectedMonth + '-01') + 'T' + selectedTime; output.change({ value: currentValue, name: name })" />{/if}<button type="button" class="wrn-next__date-done" disabled="{!currentValue}" @click="finishDate(event)">Done</button></div>
|
||||
{#if helperText}<small class="wrn-next__field-help">{helperText}</small>{/if}<small class="wrn-next__field-error" data-error="{name}">{error}</small>
|
||||
</div>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-picker-dismiss { position:fixed; inset:0; z-index:39; opacity:0; cursor:default; border:0; }
|
||||
.wrn-next__picker-clear {
|
||||
position: absolute;
|
||||
right: 2.5rem;
|
||||
@@ -116,6 +205,10 @@ size: string = "default"
|
||||
box-shadow: inset 0 0 0 1px var(--wrn-field-color);
|
||||
}
|
||||
|
||||
.wrn-next__calendar-grid button:disabled { opacity: 0.35; cursor: not-allowed; }
|
||||
.wrn-next__calendar-grid button:not(:disabled):focus-visible { outline: 2px solid var(--wrn-field-color); outline-offset: 1px; }
|
||||
.wrn-next__calendar-weekdays { padding-block: 0.375rem; }
|
||||
|
||||
/* Shared component foundation. */
|
||||
|
||||
.wrn-component {
|
||||
@@ -222,10 +315,10 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -239,9 +332,9 @@ size: string = "default"
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -283,7 +376,7 @@ size: string = "default"
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -297,10 +390,10 @@ size: string = "default"
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -408,7 +501,7 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -417,7 +510,7 @@ size: string = "default"
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -566,7 +659,7 @@ size: string = "default"
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
@@ -578,9 +671,13 @@ size: string = "default"
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
.wrn-next--date-picker, .wrn-next--time-picker { position: relative; }
|
||||
.wrn-next__calendar,
|
||||
.wrn-next__time-panel {
|
||||
z-index: 20;
|
||||
position: absolute;
|
||||
inset-block-start: calc(100% + .4rem);
|
||||
inset-inline-start: 0;
|
||||
z-index: 40;
|
||||
display: grid;
|
||||
width: min(100%, 22rem);
|
||||
gap: 0.75rem;
|
||||
@@ -588,7 +685,7 @@ size: string = "default"
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius-md);
|
||||
background: var(--wrn-color-surface);
|
||||
box-shadow: var(--wrn-shadow-3);
|
||||
box-shadow: var(--wrn-shadow-2);
|
||||
}
|
||||
.wrn-next--date-picker[data-expanded="false"] .wrn-next__calendar,
|
||||
.wrn-next--time-picker[data-expanded="false"] .wrn-next__time-panel {
|
||||
|
||||
@@ -53,6 +53,7 @@ component Divider {
|
||||
|
||||
style {
|
||||
.wrn-divider {
|
||||
border: 0;
|
||||
--divider-tone: var(--wrn-color-border);
|
||||
--divider-thickness: 1px;
|
||||
display: flex;
|
||||
|
||||
@@ -17,96 +17,32 @@ component DragAndDrop {
|
||||
variant: string = "default"
|
||||
class: string = ""
|
||||
}
|
||||
state orderedItems = items
|
||||
state draggedIndex: number = -1
|
||||
functions {
|
||||
client function startDrag(index, sourceEvent) { draggedIndex = index; sourceEvent.dataTransfer.setData("text/plain", String(index)); output.dragStart({ index: index }) }
|
||||
client function enter(sourceEvent) { sourceEvent.preventDefault(); output.dragEnter({ sourceEvent: sourceEvent }) }
|
||||
client function leave(sourceEvent) { output.dragLeave({ sourceEvent: sourceEvent }) }
|
||||
client function finish(sourceEvent) { draggedIndex = -1; output.dragEnd({ sourceEvent: sourceEvent }) }
|
||||
client function move(from, to, sourceEvent, next, moved) {
|
||||
if (from < 0 || to < 0 || to >= orderedItems.length || from === to) { return }
|
||||
next = orderedItems.slice(); moved = next.splice(from, 1)[0]; next.splice(to, 0, moved); orderedItems = next
|
||||
output.change({ value: orderedItems, sourceEvent: sourceEvent })
|
||||
}
|
||||
client function dropAt(index, sourceEvent) { sourceEvent.preventDefault(); move(draggedIndex, index, sourceEvent); draggedIndex = -1; output.drop({ index: index, items: orderedItems }) }
|
||||
}
|
||||
view {
|
||||
<section class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--drag-and-drop wrn-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wrn-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
</section>
|
||||
<section {...attrs} class="wrn-sortable {class}">{#if title}<strong>{title}</strong>{/if}{#if description}<p>{description}</p>{/if}<ol>{#each orderedItems as item, index}<li draggable="true" @dragstart="startDrag(index, event)" @dragover="enter(event)" @dragleave="leave(event)" @dragend="finish(event)" @drop="dropAt(index, event)"><span class="icon-[lucide--grip-vertical]" aria-hidden="true"></span><span>{item.label}</span><button type="button" aria-label="Move {item.label} up" disabled="{index === 0}" @click="move(index, index - 1, event)">↑</button><button type="button" aria-label="Move {item.label} down" disabled="{index === orderedItems.length - 1}" @click="move(index, index + 1, event)">↓</button></li>{/each}</ol><slot /></section>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next--drag-and-drop {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius);
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface);
|
||||
}
|
||||
.wrn-next--drag-and-drop > p { margin: 0; color: var(--wrn-color-muted); }
|
||||
.wrn-next--drag-and-drop > .wrn-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.wrn-next--drag-and-drop > .wrn-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wrn-radius-sm); background: var(--wrn-color-surface-2); }
|
||||
|
||||
/* 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;
|
||||
}
|
||||
.wrn-sortable { display:grid; gap:.75rem; color:var(--wrn-color-text); }
|
||||
.wrn-sortable p { margin:0; color:var(--wrn-color-muted); font-size:.875rem; }
|
||||
.wrn-sortable ol { display:grid; gap:.5rem; list-style:none; margin:0; padding:0; }
|
||||
.wrn-sortable li { display:flex; align-items:center; gap:.6rem; padding:.65rem; background:var(--wrn-color-surface); border:1px solid var(--wrn-color-border); border-radius:var(--wrn-radius-sm); font-size:.875rem; cursor:grab; }
|
||||
.wrn-sortable li > span:nth-child(2) { flex:1; }
|
||||
.wrn-sortable li > span:first-child { width:1rem; height:1rem; color:var(--wrn-color-muted); }
|
||||
.wrn-sortable button { border:1px solid var(--wrn-color-border); background:transparent; color:inherit; border-radius:4px; width:1.75rem; height:1.75rem; cursor:pointer; }
|
||||
.wrn-sortable button:disabled { opacity:.3; }
|
||||
}
|
||||
}
|
||||
@@ -209,12 +209,12 @@ open: boolean = false
|
||||
|
||||
.wrn-drawer__trigger {
|
||||
appearance: none;
|
||||
min-height: 2.55rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.65rem 1rem;
|
||||
color: var(--wrn-color-primary-contrast);
|
||||
background: var(--drawer-accent);
|
||||
border: 0;
|
||||
border-radius: 0.8rem;
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 650;
|
||||
|
||||
@@ -8,6 +8,7 @@ component Dropdown {
|
||||
}
|
||||
|
||||
props {
|
||||
value: string | number = ""
|
||||
items: unknown[] = []
|
||||
open: boolean = false
|
||||
defaultOpen: boolean = false
|
||||
@@ -215,7 +216,7 @@ items: unknown[] = []
|
||||
role="menuitem"
|
||||
data-dropdown-item
|
||||
data-danger='{item.danger ? "true" : "false"}'
|
||||
data-selected='{item.selected || item.checked ? "true" : "false"}'
|
||||
data-selected='{(value !== "" ? String(item.value) === String(value) : item.selected || item.checked) ? "true" : "false"}'
|
||||
aria-disabled='{item.disabled ? "true" : "false"}'
|
||||
tabindex='{item.disabled ? "-1" : "0"}'
|
||||
class="wrn-dropdown__item"
|
||||
@@ -234,7 +235,7 @@ items: unknown[] = []
|
||||
<span class="wrn-dropdown__badge">{item.badge}</span>
|
||||
{:else if item.shortcut}
|
||||
<kbd>{item.shortcut}</kbd>
|
||||
{:else if item.checked || item.selected}
|
||||
{:else if value !== "" ? String(item.value) === String(value) : item.checked || item.selected}
|
||||
<span class="icon-[lucide--check] wrn-dropdown__status" aria-hidden="true"></span>
|
||||
{:else if item.external}
|
||||
<span class="icon-[lucide--arrow-up-right] wrn-dropdown__status" aria-hidden="true"></span>
|
||||
@@ -246,7 +247,7 @@ items: unknown[] = []
|
||||
role="menuitem"
|
||||
data-dropdown-item
|
||||
data-danger='{item.danger ? "true" : "false"}'
|
||||
data-selected='{item.selected || item.checked ? "true" : "false"}'
|
||||
data-selected='{(value !== "" ? String(item.value) === String(value) : item.selected || item.checked) ? "true" : "false"}'
|
||||
disabled='{item.disabled}'
|
||||
class="wrn-dropdown__item"
|
||||
@click='chooseItem(item, itemIndex, event)'
|
||||
@@ -264,7 +265,7 @@ items: unknown[] = []
|
||||
<span class="wrn-dropdown__badge">{item.badge}</span>
|
||||
{:else if item.shortcut}
|
||||
<kbd>{item.shortcut}</kbd>
|
||||
{:else if item.checked || item.selected}
|
||||
{:else if value !== "" ? String(item.value) === String(value) : item.checked || item.selected}
|
||||
<span class="icon-[lucide--check] wrn-dropdown__status" aria-hidden="true"></span>
|
||||
{/if}
|
||||
</button>
|
||||
@@ -320,12 +321,12 @@ items: unknown[] = []
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.55rem;
|
||||
min-height: 2.55rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.65rem 0.9rem;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface-raised);
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.78rem;
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
font: inherit;
|
||||
font-size: 0.84rem;
|
||||
font-weight: 600;
|
||||
@@ -362,13 +363,13 @@ items: unknown[] = []
|
||||
}
|
||||
|
||||
.wrn-dropdown[data-size="sm"] .wrn-dropdown__trigger {
|
||||
min-height: 2.2rem;
|
||||
min-height: var(--wrn-control-height-sm, 2rem);
|
||||
padding: 0.5rem 0.72rem;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.wrn-dropdown[data-size="lg"] .wrn-dropdown__trigger {
|
||||
min-height: 2.9rem;
|
||||
min-height: var(--wrn-control-height-lg, 2.75rem);
|
||||
padding: 0.78rem 1.05rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
@@ -397,7 +398,7 @@ items: unknown[] = []
|
||||
linear-gradient(145deg, color-mix(in srgb, var(--dropdown-accent) 5%, transparent), transparent 60%),
|
||||
color-mix(in srgb, var(--wrn-color-surface-raised) 97%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--dropdown-accent) 18%, var(--wrn-color-border));
|
||||
border-radius: 1rem;
|
||||
border-radius: var(--wrn-radius-md);
|
||||
box-shadow:
|
||||
0 1px 0 color-mix(in srgb, white 5%, transparent) inset,
|
||||
0 24px 64px color-mix(in srgb, black 22%, transparent);
|
||||
|
||||
@@ -49,7 +49,6 @@ component FeatureCard {
|
||||
data-disabled='{disabled ? "true" : "false"}'
|
||||
data-stretched-link='{stretchedLink ? "true" : "false"}'
|
||||
class='wrn-feature-card {class}'
|
||||
role="listitem"
|
||||
aria-disabled='{disabled ? "true" : "false"}'
|
||||
>
|
||||
{#if image}
|
||||
|
||||
@@ -38,7 +38,7 @@ component FeatureGrid {
|
||||
style='--wrn-feature-grid-columns: {columns}; --wrn-feature-grid-tablet-columns: {tabletColumns}; --wrn-feature-grid-mobile-columns: {mobileColumns}; --wrn-feature-grid-min-item-width: {minItemWidth || "17rem"};'
|
||||
>
|
||||
<div class="wrn-feature-grid__inner">
|
||||
<div class="wrn-feature-grid__grid" role="list">
|
||||
<div class="wrn-feature-grid__grid">
|
||||
{#if items.length > 0}
|
||||
{#each items as item, itemIndex}
|
||||
<FeatureCard
|
||||
|
||||
@@ -36,10 +36,10 @@ size: string = "default"
|
||||
functions {
|
||||
client function handleChange(sourceEvent) {
|
||||
sourceEvent.stopPropagation()
|
||||
selectedName = sourceEvent.currentTarget.files && sourceEvent.currentTarget.files.length ? sourceEvent.currentTarget.files[0].name : ""
|
||||
output.input({ files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent })
|
||||
output.change({ files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent })
|
||||
if (selectedName) output.select({ files: sourceEvent.currentTarget.files, name: name, sourceEvent: sourceEvent })
|
||||
selectedName = sourceEvent.currentTarget.files && sourceEvent.currentTarget.files.length ? Array.from(sourceEvent.currentTarget.files).map(function (file) { return file.name }).join(", ") : ""
|
||||
output.input({ files: Array.from(sourceEvent.currentTarget.files || []), name: name, sourceEvent: sourceEvent })
|
||||
output.change({ files: Array.from(sourceEvent.currentTarget.files || []), name: name, sourceEvent: sourceEvent })
|
||||
if (selectedName) output.select({ files: Array.from(sourceEvent.currentTarget.files || []), name: name, sourceEvent: sourceEvent })
|
||||
else output.clear({ name: name, sourceEvent: sourceEvent })
|
||||
}
|
||||
client function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); output[nameEvent]({ name: name, sourceEvent: sourceEvent }) }
|
||||
@@ -48,15 +48,19 @@ size: string = "default"
|
||||
view {
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--file-input {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
|
||||
<div class="wrn-next__field-heading"><label class="{hiddenLabel ? 'wrn-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wrn-next__field-hint">{cornerHint}</span>{/if}</div>
|
||||
<div class="wrn-next__file-control" data-icon-position="{iconPosition}">{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}<span>{selectedName || value || placeholder}</span><input id="{id || name}" type="file" name="{name}" accept="{accept}" multiple="{multiple}" disabled="{disabled}" required="{required}" aria-readonly="{readonly}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @input="handleChange(event)" @change="handleChange(event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="emitField('invalid', event)" /></div>
|
||||
<div class="wrn-next__file-control" data-icon-position="{iconPosition}">{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}<span>{selectedName || value || placeholder}</span><input id="{id || name}" type="file" name="{name}" accept="{accept}" multiple="{multiple}" disabled="{disabled}" required="{required}" aria-readonly="{readonly}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @change="handleChange(event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="emitField('invalid', event)" /></div>
|
||||
{#if helperText}<small class="wrn-next__field-help">{helperText}</small>{/if}<small class="wrn-next__field-error" data-error="{name}">{error}</small>
|
||||
</div>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next__file-control > span:last-of-type { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
||||
.wrn-next__file-control > span:first-child:not(:last-of-type) { flex:none; width:1rem; height:1rem; }
|
||||
.wrn-next__file-control:focus-within { outline:2px solid var(--wrn-color-focus); outline-offset:2px; }
|
||||
.wrn-next__file-control {
|
||||
position: relative;
|
||||
min-height: 2.75rem;
|
||||
display:flex; align-items:center; gap:.6rem; min-width:0;
|
||||
min-height: 2.5rem;
|
||||
padding: 0.65rem 0.85rem;
|
||||
border: 1px dashed var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
@@ -67,7 +71,7 @@ size: string = "default"
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
inset: 0;
|
||||
inset: 0; width:100%; height:100%;
|
||||
}
|
||||
|
||||
/* Shared component foundation. */
|
||||
@@ -176,10 +180,10 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -193,9 +197,9 @@ size: string = "default"
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -237,7 +241,7 @@ size: string = "default"
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -251,10 +255,10 @@ size: string = "default"
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -362,7 +366,7 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -371,7 +375,7 @@ size: string = "default"
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -520,7 +524,7 @@ size: string = "default"
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -18,6 +18,7 @@ size: string = "default"
|
||||
status: string = "uploading"
|
||||
cancelLabel: string = "Cancel upload"
|
||||
retryLabel: string = "Retry upload"
|
||||
showCompleteAction: boolean = false
|
||||
class: string = ""
|
||||
}
|
||||
state currentValue = value
|
||||
@@ -34,7 +35,7 @@ size: string = "default"
|
||||
<div class="wrn-next__row"><span>{#if fileName}<strong>{fileName}</strong><small>{#if uploadedSize || fileSize}{uploadedSize}{#if uploadedSize && fileSize} of {/if}{fileSize}{:else}{label}{/if}</small>{:else}<strong>{label}</strong>{/if}</span>{#if showValue}<strong>{percent()}%</strong>{/if}</div>
|
||||
<progress value="{currentValue}" max="{max}" aria-label="{label}"></progress>
|
||||
<div class="wrn-next__upload-status"><span class="wrn-next__upload-status-icon" aria-hidden="true"></span><span>{#if currentStatus === "uploading"}Uploading securely…{:else if currentStatus === "complete"}Upload complete{:else if currentStatus === "error"}Upload failed{:else}Upload cancelled{/if}</span></div>
|
||||
<div class="wrn-next__upload-actions">{#if currentStatus === "uploading"}<button type="button" @click="cancelUpload(event)">{cancelLabel}</button><button type="button" @click="completeUpload(event)">Complete</button>{/if}{#if currentStatus === "error" || currentStatus === "cancelled"}<button type="button" @click="retryUpload(event)">{retryLabel}</button>{/if}</div>
|
||||
<div class="wrn-next__upload-actions">{#if currentStatus === "uploading"}<button type="button" @click="cancelUpload(event)">{cancelLabel}</button>{#if showCompleteAction}<button type="button" @click="completeUpload(event)">Complete</button>{/if}{/if}{#if currentStatus === "error" || currentStatus === "cancelled"}<button type="button" @click="retryUpload(event)">{retryLabel}</button>{/if}</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -190,10 +191,10 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -207,9 +208,9 @@ size: string = "default"
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -251,7 +252,7 @@ size: string = "default"
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -265,10 +266,10 @@ size: string = "default"
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -376,7 +377,7 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -385,7 +386,7 @@ size: string = "default"
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -534,7 +535,7 @@ size: string = "default"
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Badge from "./Badge.wrn"
|
||||
import Badge from "./badge.wrn"
|
||||
|
||||
component Hero {
|
||||
props {
|
||||
|
||||
@@ -53,6 +53,8 @@ component InputGroup {
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next__input-group-control > .wrn-next__field-icon { position:static; transform:none; flex:0 0 1rem; width:1rem; height:1rem; margin-inline:.75rem 0; }
|
||||
.wrn-next__input-group-control > .wrn-next__field-icon[data-position="end"] { order:2; margin-inline:0 .75rem; }
|
||||
.wrn-next__input-group-control {
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
@@ -189,10 +191,10 @@ component InputGroup {
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -206,9 +208,9 @@ component InputGroup {
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -250,7 +252,7 @@ component InputGroup {
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -264,10 +266,10 @@ component InputGroup {
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -375,7 +377,7 @@ component InputGroup {
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -384,7 +386,7 @@ component InputGroup {
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -533,7 +535,7 @@ component InputGroup {
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -13,16 +13,29 @@ component LegendIndicator {
|
||||
variant: string = "default"
|
||||
class: string = ""
|
||||
}
|
||||
state hiddenItems = []
|
||||
functions {
|
||||
client function toggleItem(item, index, sourceEvent) {
|
||||
hiddenItems = hiddenItems.includes(index) ? hiddenItems.filter(function (value) { return value !== index }) : hiddenItems.concat(index)
|
||||
output.toggle({ item: item, index: index, hidden: hiddenItems.includes(index), sourceEvent: sourceEvent })
|
||||
output.select({ value: item.value || item.label, sourceEvent: sourceEvent })
|
||||
}
|
||||
}
|
||||
view {
|
||||
<section class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--legend-indicator wrn-next--variant-{variant} {class}">
|
||||
<div class="wrn-legend {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wrn-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
</section>
|
||||
<div class="wrn-legend__items">{#each items as item, index}<button type="button" aria-pressed="{!hiddenItems.includes(index)}" @click="toggleItem(item, index, event)"><i style="background:{item.color || 'var(--wrn-color-primary)'}" aria-hidden="true"></i><span>{item.label}</span>{#if item.value}<small>{item.value}</small>{/if}</button>{/each}</div><slot />
|
||||
</div>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-legend { display:grid; gap:.65rem; }
|
||||
.wrn-legend p { margin:0; color:var(--wrn-color-muted); }
|
||||
.wrn-legend__items { display:flex; flex-wrap:wrap; gap:.75rem; }
|
||||
.wrn-legend button { display:flex; align-items:center; gap:.4rem; border:0; background:transparent; color:var(--wrn-color-text); font:inherit; font-size:.875rem; cursor:pointer; }
|
||||
.wrn-legend i { width:.65rem; height:.65rem; border-radius:50%; }
|
||||
.wrn-legend button[aria-pressed="false"] { opacity:.45; text-decoration:line-through; }
|
||||
|
||||
.wrn-next--legend-indicator {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -11,98 +11,35 @@ component ListGroup {
|
||||
description: string = ""
|
||||
items: unknown[] = []
|
||||
variant: string = "default"
|
||||
value: string = ""
|
||||
class: string = ""
|
||||
}
|
||||
state selectedValue = value
|
||||
functions {
|
||||
client function choose(item, index) {
|
||||
if (item.disabled) { return }
|
||||
selectedValue = String(item.value || index)
|
||||
output.select({ value: selectedValue, item: item, index: index })
|
||||
output.change({ value: selectedValue, item: item, index: index })
|
||||
}
|
||||
}
|
||||
view {
|
||||
<section class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--list-group wrn-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wrn-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
<section {...attrs} class="wrn-list-group {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}{#if description}<p>{description}</p>{/if}
|
||||
<div class="wrn-list-group__items" role="group" aria-label="{title}">{#each items as item, index}<button type="button" disabled="{item.disabled}" aria-pressed="{selectedValue === String(item.value || index)}" @click="choose(item, index)">{#if item.icon}<span class="{item.icon}" aria-hidden="true"></span>{/if}<span><strong>{item.label}</strong>{#if item.description}<small>{item.description}</small>{/if}</span>{#if item.badge}<span class="wrn-list-group__badge">{item.badge}</span>{/if}</button>{/each}</div><slot />
|
||||
</section>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next--list-group {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius);
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface);
|
||||
}
|
||||
.wrn-next--list-group > p { margin: 0; color: var(--wrn-color-muted); }
|
||||
.wrn-next--list-group > .wrn-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.wrn-next--list-group > .wrn-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wrn-radius-sm); background: var(--wrn-color-surface-2); }
|
||||
|
||||
/* 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;
|
||||
}
|
||||
.wrn-list-group { display:grid; gap:.75rem; color:var(--wrn-color-text); }
|
||||
.wrn-list-group > p { margin:0; font-size:.875rem; color:var(--wrn-color-muted); }
|
||||
.wrn-list-group__items { border:1px solid var(--wrn-color-border); border-radius:var(--wrn-radius-md); overflow:hidden; }
|
||||
.wrn-list-group button { display:flex; align-items:center; gap:.75rem; width:100%; padding:.85rem 1rem; text-align:start; border:0; color:inherit; background:var(--wrn-color-surface); font:inherit; font-size:.875rem; cursor:pointer; }
|
||||
.wrn-list-group button + button { border-top:1px solid var(--wrn-color-border); }
|
||||
.wrn-list-group button[aria-pressed="true"] { background:var(--wrn-color-primary-soft); color:var(--wrn-color-primary-text); }
|
||||
.wrn-list-group button > [class*="icon-"] { width:1.1rem; height:1.1rem; flex:none; }
|
||||
.wrn-list-group small { display:block; margin-top:.2rem; color:var(--wrn-color-muted); font-size:.8rem; }
|
||||
.wrn-list-group__badge { margin-inline-start:auto; font-size:.75rem; }
|
||||
.wrn-list-group button:disabled { opacity:.5; cursor:not-allowed; }
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,30 @@ component Map {
|
||||
description: string = ""
|
||||
items: unknown[] = []
|
||||
variant: string = "default"
|
||||
provider: string = "openstreetmap"
|
||||
apiKey: string = ""
|
||||
query: string = ""
|
||||
latitude: number = 12.9716
|
||||
longitude: number = 77.5946
|
||||
zoomLevel: number = 13
|
||||
mapType: string = "roadmap"
|
||||
imageSrc: string = ""
|
||||
imageAlt: string = "Map background"
|
||||
class: string = ""
|
||||
}
|
||||
|
||||
state imageZoom: number = 1
|
||||
state selectedLabel: string = ""
|
||||
functions {
|
||||
shared function mapUrl() {
|
||||
if (provider === "google") { return "https://www.google.com/maps/embed/v1/place?key=" + encodeURIComponent(apiKey) + "&q=" + encodeURIComponent(query || latitude + "," + longitude) + "&zoom=" + Math.max(1, Math.min(21, zoomLevel)) + "&maptype=" + (mapType === "satellite" ? "satellite" : "roadmap") }
|
||||
var span = 360 / Math.pow(2, Math.max(1, Math.min(18, zoomLevel)))
|
||||
return "https://www.openstreetmap.org/export/embed.html?bbox=" + (longitude - span) + "," + (latitude - span / 2) + "," + (longitude + span) + "," + (latitude + span / 2) + "&layer=mapnik&marker=" + latitude + "," + longitude
|
||||
}
|
||||
|
||||
client function changeZoom(direction) { imageZoom = Math.max(1, Math.min(3, imageZoom + direction * .25)); output.zoom({ level: imageZoom, direction: direction > 0 ? "in" : "out" }) }
|
||||
client function chooseMarker(item) { selectedLabel = item.label || item.title || "Location"; output.markerClick(item); output.select(item) }
|
||||
}
|
||||
view {
|
||||
<section
|
||||
data-ui-component="Map"
|
||||
@@ -42,6 +63,10 @@ component Map {
|
||||
class="wrn-map__viewport"
|
||||
data-size='{size}'
|
||||
>
|
||||
{#if !imageSrc}
|
||||
{#if provider === "google" && !apiKey}<p class="wrn-map__selection">Add your Google Maps Embed API key to display this map.</p>{:else}<iframe title="{title || 'Location map'}" src="{mapUrl()}" loading="lazy" referrerpolicy="no-referrer-when-downgrade" allowfullscreen style="width:100%;height:100%;min-height:320px;border:0"></iframe>{/if}
|
||||
{:else}<div class="wrn-map__canvas" style="transform:scale({imageZoom})">
|
||||
{#if imageSrc}<img class="wrn-map__image" src="{imageSrc}" alt="{imageAlt}" />{/if}
|
||||
<div
|
||||
class="wrn-map__grid"
|
||||
style="background-image: linear-gradient(var(--wrn-color-border) 1px, transparent 1px), linear-gradient(90deg, var(--wrn-color-border) 1px, transparent 1px); background-size: 32px 32px;"
|
||||
@@ -59,19 +84,21 @@ component Map {
|
||||
aria-label='{item.label || item.title || "Map marker"}'
|
||||
class="wrn-map__marker"
|
||||
style='left: {item.x || (20 + index * 12)}%; top: {item.y || (30 + (index % 3) * 18)}%;'
|
||||
@click='output.markerClick(item); output.select(item)'
|
||||
@click='chooseMarker(item)'
|
||||
>
|
||||
<span class='{item.icon || "icon-[lucide--map-pin]"}' aria-hidden="true"></span>
|
||||
</button>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
{#if selectedLabel}<output class="wrn-map__selection">{selectedLabel}</output>{/if}
|
||||
<div class="wrn-map__controls">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Zoom in"
|
||||
class="wrn-map__control"
|
||||
@click='output.zoom({ direction: "in" })'
|
||||
@click='changeZoom(1)'
|
||||
>
|
||||
<span class="icon-[lucide--plus] wrn-map__control-icon" aria-hidden="true"></span>
|
||||
</button>
|
||||
@@ -79,16 +106,22 @@ component Map {
|
||||
type="button"
|
||||
aria-label="Zoom out"
|
||||
class="wrn-map__control"
|
||||
@click='output.zoom({ direction: "out" })'
|
||||
@click='changeZoom(-1)'
|
||||
>
|
||||
<span class="icon-[lucide--minus] wrn-map__control-icon" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>{/if}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-map__canvas { position:absolute; inset:0; transition:transform 160ms ease; }
|
||||
.wrn-map__image { width:100%; height:100%; object-fit:cover; }
|
||||
.wrn-map__canvas:has(.wrn-map__image) .wrn-map__grid { display:none; }
|
||||
.wrn-map__selection { position:absolute; inset-inline-start:1rem; bottom:1rem; padding:.5rem .75rem; border-radius:6px; background:var(--wrn-color-surface); color:var(--wrn-color-text); font-size:.875rem; }
|
||||
.wrn-map__marker > span { width:1.1rem; height:1.1rem; }
|
||||
|
||||
.wrn-map { overflow: hidden; border: 1px solid var(--wrn-color-border); border-radius: calc(var(--wrn-radius) * 1.5); background: var(--wrn-color-surface-raised); box-shadow: var(--wrn-shadow-1); }
|
||||
.wrn-map__header { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: 1.25rem; border-bottom: 1px solid var(--wrn-color-border); }
|
||||
.wrn-map__title { color: var(--wrn-color-text); font-size: 1.125rem; font-weight: 700; }
|
||||
|
||||
@@ -193,12 +193,12 @@ component MegaMenu {
|
||||
class="wrn-mega__trigger"
|
||||
aria-haspopup="true"
|
||||
aria-expanded='{visible}'
|
||||
aria-label='{label}'
|
||||
aria-label='{label || "Menu"}'
|
||||
@click='activatePanel(event)'
|
||||
@mouseenter='hoverPanel(event)'
|
||||
>
|
||||
<span class='wrn-mega__trigger-icon {icon}' data-show="icon" aria-hidden="true"></span>
|
||||
<span class="wrn-mega__trigger-label" data-label='{label}' aria-hidden="true"></span>
|
||||
<span class="wrn-mega__trigger-label" data-label='{label || "Menu"}' aria-hidden="true"></span>
|
||||
<span class="wrn-mega__arrow" aria-hidden="true">›</span>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ component MetricCard {
|
||||
size: string = "default"
|
||||
color: string = "primary"
|
||||
variant: string = "default"
|
||||
hover: string = "lift"
|
||||
hover: string = "none"
|
||||
align: string = "left"
|
||||
class: string = ""
|
||||
}
|
||||
@@ -211,7 +211,7 @@ component MetricCard {
|
||||
--metric-accent-soft: var(--wrn-color-primary-soft);
|
||||
--metric-accent-muted: var(--wrn-color-primary-muted);
|
||||
--metric-contrast: var(--wrn-color-primary-contrast);
|
||||
--metric-border: color-mix(in srgb, var(--metric-accent) 16%, var(--wrn-color-border));
|
||||
--metric-border: var(--wrn-color-border);
|
||||
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
@@ -220,20 +220,12 @@ component MetricCard {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
padding: 1.5rem;
|
||||
padding: var(--wrn-space-panel, 1.25rem);
|
||||
color: var(--wrn-color-text);
|
||||
background:
|
||||
radial-gradient(
|
||||
circle at 100% 0%,
|
||||
color-mix(in srgb, var(--metric-accent) 8%, transparent),
|
||||
transparent 36%
|
||||
),
|
||||
var(--wrn-color-surface-raised);
|
||||
background: var(--wrn-color-surface);
|
||||
border: 1px solid var(--metric-border);
|
||||
border-radius: 1.25rem;
|
||||
box-shadow:
|
||||
0 1px 0 color-mix(in srgb, white 4%, transparent) inset,
|
||||
0 14px 36px color-mix(in srgb, black 10%, transparent);
|
||||
border-radius: var(--wrn-radius-md);
|
||||
box-shadow: none;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
transform 180ms ease,
|
||||
@@ -288,8 +280,8 @@ component MetricCard {
|
||||
}
|
||||
|
||||
.wrn-metric-card[data-size="lg"] {
|
||||
padding: 1.9rem;
|
||||
border-radius: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
border-radius: var(--wrn-radius-lg);
|
||||
}
|
||||
|
||||
.wrn-metric-card[data-variant="soft"] {
|
||||
@@ -464,7 +456,7 @@ component MetricCard {
|
||||
align-items: baseline;
|
||||
gap: 0.2rem;
|
||||
width: 100%;
|
||||
margin-top: 1.15rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.wrn-metric-card[data-align="center"] .wrn-metric-card__value-row {
|
||||
@@ -477,7 +469,7 @@ component MetricCard {
|
||||
|
||||
.wrn-metric-card__value {
|
||||
color: var(--wrn-color-text);
|
||||
font-size: clamp(2rem, 5vw, 2.8rem);
|
||||
font-size: clamp(1.75rem, 3vw, 2rem);
|
||||
font-weight: 700;
|
||||
line-height: 0.98;
|
||||
letter-spacing: -0.045em;
|
||||
@@ -486,11 +478,11 @@ component MetricCard {
|
||||
}
|
||||
|
||||
.wrn-metric-card[data-size="sm"] .wrn-metric-card__value {
|
||||
font-size: clamp(1.65rem, 4vw, 2.15rem);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.wrn-metric-card[data-size="lg"] .wrn-metric-card__value {
|
||||
font-size: clamp(2.45rem, 6vw, 3.5rem);
|
||||
font-size: clamp(2rem, 4vw, 2.5rem);
|
||||
}
|
||||
|
||||
.wrn-metric-card[data-variant="solid"] .wrn-metric-card__value {
|
||||
@@ -513,8 +505,8 @@ component MetricCard {
|
||||
max-width: 38rem;
|
||||
margin: 0.8rem 0 0;
|
||||
color: var(--wrn-color-text-muted);
|
||||
font-size: 0.86rem;
|
||||
line-height: 1.7;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.wrn-metric-card__progress-block {
|
||||
|
||||
@@ -18,6 +18,7 @@ component Modal {
|
||||
placement: string = "center"
|
||||
color: string = "primary"
|
||||
variant: string = "default"
|
||||
showHeader: boolean = true
|
||||
showClose: boolean = true
|
||||
closeLabel: string = "Close modal"
|
||||
closeOnBackdrop: boolean = true
|
||||
@@ -98,7 +99,7 @@ component Modal {
|
||||
<div
|
||||
{...attrs}
|
||||
data-ui-component="Modal"
|
||||
data-open='{isOpen() ? "true" : "false"}'
|
||||
data-open='{(open || visible) ? "true" : "false"}'
|
||||
data-size='{size}'
|
||||
data-placement='{placement}'
|
||||
data-color='{color}'
|
||||
@@ -107,6 +108,7 @@ component Modal {
|
||||
data-scroll='{scrollBehavior}'
|
||||
data-destructive='{destructive ? "true" : "false"}'
|
||||
class='wrn-modal {class}'
|
||||
@click="if (event.target.closest('[data-modal-close]')) { hideModal('custom-button', event) }"
|
||||
@wrnexus:modal:close='hideModal("api", event)'
|
||||
>
|
||||
{#if triggerLabel}
|
||||
@@ -114,7 +116,7 @@ component Modal {
|
||||
type="button"
|
||||
class="wrn-modal__trigger"
|
||||
aria-haspopup="dialog"
|
||||
aria-expanded='{isOpen() ? "true" : "false"}'
|
||||
aria-expanded='{(open || visible) ? "true" : "false"}'
|
||||
@click='showModal(event)'
|
||||
>
|
||||
{#if triggerIcon}
|
||||
@@ -140,7 +142,7 @@ component Modal {
|
||||
|
||||
<div
|
||||
class="wrn-modal__layer"
|
||||
data-show="isOpen()"
|
||||
data-show="(open || visible)"
|
||||
role="presentation"
|
||||
@keydown='handleKeydown(event)'
|
||||
>
|
||||
@@ -159,7 +161,7 @@ component Modal {
|
||||
aria-label='{label || title}'
|
||||
tabindex="-1"
|
||||
>
|
||||
<header
|
||||
{#if showHeader}<header
|
||||
class="wrn-modal__header"
|
||||
>
|
||||
<div
|
||||
@@ -212,7 +214,7 @@ component Modal {
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
</header>
|
||||
</header>{/if}
|
||||
|
||||
<div
|
||||
class="wrn-modal__body"
|
||||
@@ -343,12 +345,12 @@ component Modal {
|
||||
|
||||
.wrn-modal__trigger {
|
||||
appearance: none;
|
||||
min-height: 2.55rem;
|
||||
min-height: var(--wrn-control-height);
|
||||
padding: 0.65rem 1rem;
|
||||
color: var(--modal-contrast);
|
||||
background: var(--modal-accent);
|
||||
border: 0;
|
||||
border-radius: 0.8rem;
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 650;
|
||||
@@ -431,18 +433,10 @@ component Modal {
|
||||
width: min(32rem, calc(100vw - 2rem));
|
||||
max-height: min(88vh, 52rem);
|
||||
color: var(--wrn-color-text);
|
||||
background:
|
||||
radial-gradient(
|
||||
circle at 100% 0%,
|
||||
color-mix(in srgb, var(--modal-accent) 9%, transparent),
|
||||
transparent 34%
|
||||
),
|
||||
var(--wrn-color-surface-raised);
|
||||
border: 1px solid color-mix(in srgb, var(--modal-accent) 18%, var(--wrn-color-border));
|
||||
border-radius: 1.35rem;
|
||||
box-shadow:
|
||||
0 1px 0 color-mix(in srgb, white 5%, transparent) inset,
|
||||
0 40px 110px color-mix(in srgb, black 38%, transparent);
|
||||
background: var(--wrn-color-surface-raised);
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius-lg);
|
||||
box-shadow: var(--wrn-shadow-lg);
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
transform: scale(0.96) translateY(10px);
|
||||
@@ -502,7 +496,7 @@ component Modal {
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 1.4rem 1.4rem 1.15rem;
|
||||
padding: 1.25rem;
|
||||
border-bottom: 1px solid var(--wrn-color-border);
|
||||
}
|
||||
|
||||
@@ -631,7 +625,7 @@ component Modal {
|
||||
.wrn-modal__body {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
padding: 1.4rem;
|
||||
padding: 1.25rem;
|
||||
color: var(--wrn-color-text);
|
||||
}
|
||||
|
||||
@@ -659,7 +653,7 @@ component Modal {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 1rem 1.4rem 1.4rem;
|
||||
padding: 1rem 1.25rem;
|
||||
border-top: 1px solid var(--wrn-color-border);
|
||||
}
|
||||
|
||||
@@ -681,9 +675,9 @@ component Modal {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
min-height: 2.55rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.65rem 1rem;
|
||||
border-radius: 0.78rem;
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
font: inherit;
|
||||
font-size: 0.83rem;
|
||||
font-weight: 650;
|
||||
|
||||
@@ -639,7 +639,7 @@ size: string = "default"
|
||||
padding: 0.65rem;
|
||||
align-items: flex-start;
|
||||
gap: 0.65rem;
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
font-size: 0.8rem;
|
||||
font-weight: 450;
|
||||
}
|
||||
|
||||
@@ -387,6 +387,7 @@ current: true
|
||||
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.35), transparent 78%);
|
||||
}
|
||||
|
||||
.wrn-page-header[data-variant="default"] .wrn-page-header__decoration,
|
||||
.wrn-page-header[data-variant="minimal"] .wrn-page-header__decoration,
|
||||
.wrn-page-header[data-compact="true"] .wrn-page-header__grid-pattern {
|
||||
display: none;
|
||||
@@ -404,7 +405,7 @@ current: true
|
||||
width: 100%;
|
||||
max-width: 80rem;
|
||||
margin-inline: auto;
|
||||
padding: 1.25rem 1rem 2.75rem;
|
||||
padding: 1.25rem 1rem;
|
||||
}
|
||||
|
||||
.wrn-page-header[data-max-width="compact"] .wrn-page-header__inner,
|
||||
@@ -423,11 +424,11 @@ current: true
|
||||
|
||||
.wrn-page-header[data-compact="true"] .wrn-page-header__inner {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1.75rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.wrn-page-header[data-size="lg"] .wrn-page-header__inner {
|
||||
padding-bottom: 3.5rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.wrn-page-header__breadcrumb {
|
||||
@@ -518,9 +519,9 @@ current: true
|
||||
margin: 0;
|
||||
color: var(--page-header-accent-text);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 800;
|
||||
font-weight: 600;
|
||||
line-height: 1.3;
|
||||
letter-spacing: 0.16em;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@@ -538,27 +539,27 @@ current: true
|
||||
max-width: 54rem;
|
||||
margin: 0;
|
||||
color: var(--wrn-color-text);
|
||||
font-size: clamp(2rem, 4vw, 3.75rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.08;
|
||||
font-size: clamp(1.5rem, 2.2vw, 1.75rem);
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
letter-spacing: -0.035em;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.wrn-page-header[data-compact="true"] .wrn-page-header__title {
|
||||
font-size: clamp(1.75rem, 3vw, 2.65rem);
|
||||
font-size: 1.375rem;
|
||||
}
|
||||
|
||||
.wrn-page-header[data-size="lg"] .wrn-page-header__title {
|
||||
font-size: clamp(2.35rem, 5vw, 4.5rem);
|
||||
font-size: clamp(1.75rem, 3vw, 2.25rem);
|
||||
}
|
||||
|
||||
.wrn-page-header__description {
|
||||
max-width: 48rem;
|
||||
margin: 0.9rem 0 0;
|
||||
margin: 0.5rem 0 0;
|
||||
color: var(--wrn-color-text-muted);
|
||||
font-size: 1rem;
|
||||
line-height: 1.75;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.6;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
@@ -663,7 +664,7 @@ current: true
|
||||
.wrn-page-header__layout {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: start;
|
||||
gap: 2.5rem;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.wrn-page-header[data-align="center"] .wrn-page-header__layout,
|
||||
|
||||
@@ -262,6 +262,9 @@ component Pagination {
|
||||
|
||||
.wrn-pagination__pages {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
margin: 0;
|
||||
|
||||
@@ -165,6 +165,9 @@ component PinInput {
|
||||
|
||||
.wrn-next__pin-cells {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
align-items: center;
|
||||
gap: clamp(0.35rem, 1.5vw, 0.65rem);
|
||||
@@ -174,18 +177,18 @@ component PinInput {
|
||||
}
|
||||
|
||||
.wrn-next--pin-input .wrn-next__pin-cells input {
|
||||
flex: 0 0 clamp(2.4rem, 8vw, 3.25rem);
|
||||
width: clamp(2.4rem, 8vw, 3.25rem);
|
||||
height: clamp(2.75rem, 9vw, 3.5rem);
|
||||
min-width: clamp(2.4rem, 8vw, 3.25rem);
|
||||
flex: 0 1 2.5rem;
|
||||
width: 2.5rem;
|
||||
height: var(--wrn-control-height, 2.5rem);
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
font: inherit;
|
||||
font-size: clamp(1rem, 3vw, 1.25rem);
|
||||
font-weight: 750;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
caret-color: var(--wrn-component-color);
|
||||
transition:
|
||||
@@ -229,9 +232,9 @@ component PinInput {
|
||||
}
|
||||
.wrn-next--pin-input .wrn-next__pin-cells input {
|
||||
flex-basis: min(2.7rem, 12vw);
|
||||
width: min(2.7rem, 12vw);
|
||||
min-width: min(2.7rem, 12vw);
|
||||
height: min(3rem, 14vw);
|
||||
width: min(2.5rem, 10vw);
|
||||
min-width: 0;
|
||||
height: var(--wrn-control-height, 2.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -248,12 +248,12 @@ component Popover {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.55rem;
|
||||
min-height: 2.55rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.65rem 0.9rem;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface-raised);
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.78rem;
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
font: inherit;
|
||||
font-size: 0.84rem;
|
||||
font-weight: 600;
|
||||
@@ -276,13 +276,13 @@ component Popover {
|
||||
}
|
||||
|
||||
.wrn-popover[data-size="sm"] .wrn-popover__trigger {
|
||||
min-height: 2.2rem;
|
||||
min-height: var(--wrn-control-height-sm, 2rem);
|
||||
padding: 0.5rem 0.72rem;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.wrn-popover[data-size="lg"] .wrn-popover__trigger {
|
||||
min-height: 2.9rem;
|
||||
min-height: var(--wrn-control-height-lg, 2.75rem);
|
||||
padding: 0.78rem 1.05rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
@@ -309,7 +309,7 @@ component Popover {
|
||||
linear-gradient(145deg, color-mix(in srgb, var(--popover-accent) 5%, transparent), transparent 62%),
|
||||
color-mix(in srgb, var(--wrn-color-surface-raised) 97%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--popover-accent) 18%, var(--wrn-color-border));
|
||||
border-radius: 1rem;
|
||||
border-radius: var(--wrn-radius-md);
|
||||
box-shadow:
|
||||
0 1px 0 color-mix(in srgb, white 5%, transparent) inset,
|
||||
0 24px 64px color-mix(in srgb, black 22%, transparent);
|
||||
|
||||
@@ -121,20 +121,15 @@ component PortalDashboard {
|
||||
|
||||
.wrn-portal-dashboard__hero {
|
||||
display: flex;
|
||||
padding: clamp(1.25rem, 3vw, 2rem);
|
||||
padding: 0 0 1.25rem;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 1rem;
|
||||
background:
|
||||
radial-gradient(
|
||||
circle at 85% 0%,
|
||||
color-mix(in srgb, var(--wrn-color-primary) 20%, transparent),
|
||||
transparent 34%
|
||||
),
|
||||
var(--wrn-color-surface);
|
||||
box-shadow: var(--wrn-shadow-sm);
|
||||
border: 0;
|
||||
border-bottom: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.wrn-portal-dashboard__eyebrow,
|
||||
@@ -148,7 +143,7 @@ component PortalDashboard {
|
||||
|
||||
.wrn-portal-dashboard__hero h1 {
|
||||
margin: 0.35rem 0 0;
|
||||
font-size: clamp(1.4rem, 3vw, 2.25rem);
|
||||
font-size: clamp(1.375rem, 2vw, 1.75rem);
|
||||
font-weight: 650;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
@@ -177,7 +172,7 @@ component PortalDashboard {
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.85rem;
|
||||
background: var(--wrn-color-surface);
|
||||
box-shadow: var(--wrn-shadow-sm);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.wrn-portal-dashboard__metric-icon {
|
||||
@@ -221,9 +216,9 @@ component PortalDashboard {
|
||||
min-width: 0;
|
||||
padding: 1.1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.9rem;
|
||||
border-radius: var(--wrn-radius-md);
|
||||
background: var(--wrn-color-surface);
|
||||
box-shadow: var(--wrn-shadow-sm);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.wrn-portal-dashboard__panel--actions {
|
||||
|
||||
@@ -113,7 +113,7 @@ size: string = "default"
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
color: var(--wrn-color-muted);
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
|
||||
@@ -36,20 +36,52 @@ component RangeSlider {
|
||||
}
|
||||
state currentValue = value
|
||||
functions {
|
||||
shared function snapValue(raw) {
|
||||
var increment = Math.max(0.0001, Number(step))
|
||||
var snapped = Number(min) + Math.round((Number(raw) - Number(min)) / increment) * increment
|
||||
var bounded = Math.min(Number(max), Math.max(Number(min), snapped))
|
||||
return Math.round(bounded * 1000000) / 1000000
|
||||
}
|
||||
|
||||
shared function percent() { if (Number(max) === Number(min)) { return 0 } return (Number(currentValue) - Number(min)) / (Number(max) - Number(min)) * 100 }
|
||||
client function setValue(nextValue, sourceEvent, commit, detail, root, slider, input, outputElement, progressValue) { if (readonly || disabled) { return } currentValue = Number(nextValue); root = sourceEvent.currentTarget.closest(".wrn-next--range-slider"); if (root) { slider = root.querySelector("[role=slider]"); input = root.querySelector("input[name='" + name + "']"); outputElement = root.querySelector("output"); progressValue = (currentValue - Number(min)) / (Number(max) - Number(min)) * 100; if (slider) { slider.setAttribute("aria-valuenow", String(currentValue)); slider.style.setProperty("--wrn-range-progress", progressValue + "%") } if (input) { input.value = String(currentValue) } if (outputElement) { outputElement.textContent = String(currentValue) } } detail = { value: currentValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; output.input(detail); if (commit) { output.change(detail) } }
|
||||
client function setValue(nextValue, sourceEvent, commit, detail, root, slider, input, outputElement, progressValue) { if (sourceEvent.currentTarget.closest(".wrn-next--range-slider").dataset.readonly === "true" || sourceEvent.currentTarget.closest(".wrn-next--range-slider").dataset.disabled === "true") { return } currentValue = Number(nextValue); root = sourceEvent.currentTarget.closest(".wrn-next--range-slider"); if (root) { slider = root.querySelector("[role=slider]"); input = root.querySelector("input[name='" + name + "']"); outputElement = root.querySelector("output"); progressValue = (currentValue - Number(min)) / (Number(max) - Number(min)) * 100; if (slider) { slider.setAttribute("aria-valuenow", String(currentValue)); slider.style.setProperty("--wrn-range-progress", progressValue + "%") } if (input) { input.value = String(currentValue) } if (outputElement) { outputElement.textContent = String(currentValue) } } detail = { value: currentValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; output.input(detail); if (commit) { output.change(detail) } }
|
||||
client function valueFromPointer(sourceEvent, rect, ratio) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); return Number(min) + ratio * (Number(max) - Number(min)) }
|
||||
client function beginSlide(sourceEvent, rect, ratio, rawValue) { if (readonly || disabled) { return } sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId); rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function moveSlide(sourceEvent, rect, ratio, rawValue) { if (!sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { return } rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function endSlide(sourceEvent, rect, ratio, rawValue) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = Number(min) + Math.round((rawValue - Number(min)) / Number(step)) * Number(step); if (sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { sourceEvent.currentTarget.releasePointerCapture(sourceEvent.pointerId) } output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function selectMark(sourceEvent, root, slider, input, outputElement, nextValue, progressValue, detail) { if (readonly || disabled) { return } root = sourceEvent.currentTarget.closest(".wrn-next--range-slider"); slider = root.querySelector(".wrn-next__custom-slider"); input = root.querySelector(".wrn-next__range-value"); outputElement = root.querySelector("output"); nextValue = Number(sourceEvent.currentTarget.dataset.value); currentValue = nextValue; progressValue = (nextValue - Number(min)) / (Number(max) - Number(min)) * 100; slider.setAttribute("aria-valuenow", String(nextValue)); slider.style.setProperty("--wrn-range-progress", progressValue + "%"); input.setAttribute("value", String(nextValue)); outputElement.replaceChildren(String(nextValue)); detail = { value: nextValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; output.input(detail); output.change(detail) }
|
||||
client function handleKey(sourceEvent) { if (sourceEvent.key === "ArrowRight") { sourceEvent.preventDefault(); currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }); output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "ArrowLeft") { sourceEvent.preventDefault(); currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }); output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "Home") { sourceEvent.preventDefault(); currentValue = Number(min); output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) } if (sourceEvent.key === "End") { sourceEvent.preventDefault(); currentValue = Number(max); output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) } }
|
||||
client function beginSlide(sourceEvent, rect, ratio, rawValue) { if (sourceEvent.currentTarget.closest(".wrn-next--range-slider").dataset.readonly === "true" || sourceEvent.currentTarget.closest(".wrn-next--range-slider").dataset.disabled === "true") { return } sourceEvent.currentTarget.setPointerCapture(sourceEvent.pointerId); rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = snapValue(rawValue); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function moveSlide(sourceEvent, rect, ratio, rawValue) { if (!sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { return } rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = snapValue(rawValue); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function endSlide(sourceEvent, rect, ratio, rawValue) { rect = sourceEvent.currentTarget.getBoundingClientRect(); ratio = Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)); rawValue = Number(min) + ratio * (Number(max) - Number(min)); currentValue = snapValue(rawValue); if (sourceEvent.currentTarget.hasPointerCapture(sourceEvent.pointerId)) { sourceEvent.currentTarget.releasePointerCapture(sourceEvent.pointerId) } output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function selectMark(sourceEvent, root, slider, input, outputElement, nextValue, progressValue, detail) { if (sourceEvent.currentTarget.closest(".wrn-next--range-slider").dataset.readonly === "true" || sourceEvent.currentTarget.closest(".wrn-next--range-slider").dataset.disabled === "true") { return } root = sourceEvent.currentTarget.closest(".wrn-next--range-slider"); slider = root.querySelector(".wrn-next__custom-slider"); input = root.querySelector(".wrn-next__range-value"); outputElement = root.querySelector("output"); nextValue = Number(sourceEvent.currentTarget.dataset.value); currentValue = nextValue; progressValue = (nextValue - Number(min)) / (Number(max) - Number(min)) * 100; slider.setAttribute("aria-valuenow", String(nextValue)); slider.style.setProperty("--wrn-range-progress", progressValue + "%"); input.setAttribute("value", String(nextValue)); outputElement.replaceChildren(String(nextValue)); detail = { value: nextValue, min: min, max: max, step: step, name: name, sourceEvent: sourceEvent }; output.input(detail); output.change(detail) }
|
||||
client function handleKey(sourceEvent) {
|
||||
if (readonly || disabled) { return }
|
||||
var next = Number(currentValue)
|
||||
if (sourceEvent.key === "ArrowRight" || sourceEvent.key === "ArrowUp") { next = next + Number(step) }
|
||||
else if (sourceEvent.key === "ArrowLeft" || sourceEvent.key === "ArrowDown") { next = next - Number(step) }
|
||||
else if (sourceEvent.key === "Home") { next = Number(min) }
|
||||
else if (sourceEvent.key === "End") { next = Number(max) }
|
||||
else { return }
|
||||
sourceEvent.preventDefault()
|
||||
currentValue = snapValue(next)
|
||||
output.input({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
output.change({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
}
|
||||
client function emitFocus(nameEvent, sourceEvent) { output[nameEvent]({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function decreaseValue(sourceEvent) { currentValue = Math.max(Number(min), Number(currentValue) - Number(step)); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }); output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function increaseValue(sourceEvent) { currentValue = Math.min(Number(max), Number(currentValue) + Number(step)); output.input({ value: currentValue, name: name, sourceEvent: sourceEvent }); output.change({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function decreaseValue(sourceEvent) {
|
||||
if (readonly || disabled) { return }
|
||||
var next = Math.max(Number(min), Number(currentValue) - Number(step))
|
||||
currentValue = Math.round(next * 1000000) / 1000000
|
||||
output.input({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
output.change({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
}
|
||||
client function increaseValue(sourceEvent) {
|
||||
if (readonly || disabled) { return }
|
||||
var next = Math.min(Number(max), Number(currentValue) + Number(step))
|
||||
currentValue = Math.round(next * 1000000) / 1000000
|
||||
output.input({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
output.change({ value: currentValue, name: name, sourceEvent: sourceEvent })
|
||||
}
|
||||
|
||||
}
|
||||
view {
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--range-slider {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--range-slider {class}" data-readonly="{readonly}" data-disabled="{disabled}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
|
||||
<div class="wrn-next__field-heading"><label class="{hiddenLabel ? 'wrn-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wrn-next__field-hint">{cornerHint}</span>{/if}</div>
|
||||
<div class="wrn-next__range-control" data-variant="{variant}" data-icon-position="{iconPosition}" data-show-steps="{showSteps}">
|
||||
{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}
|
||||
@@ -70,7 +102,10 @@ component RangeSlider {
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next__range-control { align-items:center; padding-bottom:1.5rem; }
|
||||
.wrn-next__range-bounds { position:absolute; top:calc(100% + .25rem); left:0; right:0; }
|
||||
.wrn-next__range-track {
|
||||
position:relative;
|
||||
display: grid;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
@@ -311,10 +346,10 @@ component RangeSlider {
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -328,9 +363,9 @@ component RangeSlider {
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -372,7 +407,7 @@ component RangeSlider {
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -386,10 +421,10 @@ component RangeSlider {
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -497,7 +532,7 @@ component RangeSlider {
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -506,7 +541,7 @@ component RangeSlider {
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -655,7 +690,7 @@ component RangeSlider {
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -11,98 +11,50 @@ component Rating {
|
||||
description: string = ""
|
||||
items: unknown[] = []
|
||||
variant: string = "default"
|
||||
value: number = 0
|
||||
max: number = 5
|
||||
step: number = 1
|
||||
readonly: boolean = false
|
||||
disabled: boolean = false
|
||||
class: string = ""
|
||||
}
|
||||
state selectedValue = value
|
||||
functions {
|
||||
shared function stars() { return Array.from({ length: Math.max(1, Math.min(10, max)) }) }
|
||||
client function choose(index, sourceEvent) {
|
||||
if (readonly || disabled) { return }
|
||||
var rect = sourceEvent.currentTarget.getBoundingClientRect()
|
||||
var fraction = sourceEvent.detail > 0 && rect.width ? Math.max(0, Math.min(1, (sourceEvent.clientX - rect.left) / rect.width)) : 1
|
||||
var increment = Math.max(0.01, Number(step))
|
||||
var next = Math.ceil((index + fraction) / increment) * increment
|
||||
selectedValue = Number(Math.min(max, Math.max(0, next)).toFixed(2))
|
||||
output.input({ value: selectedValue, sourceEvent: sourceEvent })
|
||||
output.change({ value: selectedValue, sourceEvent: sourceEvent })
|
||||
}
|
||||
}
|
||||
view {
|
||||
<section class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--rating wrn-next--variant-{variant} {class}">
|
||||
<div {...attrs} class="wrn-rating {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wrn-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
</section>
|
||||
<div role="group" aria-label="{title || 'Rating'}" class="wrn-rating__stars">
|
||||
{#each stars() as star, index}<button type="button" aria-label="Rate {index + 1} of {max}" aria-pressed="{selectedValue === index + 1}" disabled="{disabled || readonly}" data-filled="{index < selectedValue}" style="--fill:{Math.max(0, Math.min(1, selectedValue - index)) * 100}%" @click="choose(index, event)"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m12 3 2.8 5.7 6.2.9-4.5 4.4 1.1 6.2-5.6-3-5.6 3 1.1-6.2L3 9.6l6.2-.9Z" /></svg><svg class="wrn-rating__fill" viewBox="0 0 24 24" aria-hidden="true"><path d="m12 3 2.8 5.7 6.2.9-4.5 4.4 1.1 6.2-5.6-3-5.6 3 1.1-6.2L3 9.6l6.2-.9Z" /></svg></button>{/each}
|
||||
<input class="wrn-rating__precise" type="range" aria-label="Precise rating" min="0" max="{max}" step="{step}" value="{selectedValue}" disabled="{disabled || readonly}" @input="selectedValue = Number(event.currentTarget.value); output.input({ value: selectedValue })" @change="output.change({ value: selectedValue })" /><output aria-live="polite">{selectedValue} / {max}</output>
|
||||
</div><slot />
|
||||
</div>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next--rating {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius);
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface);
|
||||
}
|
||||
.wrn-next--rating > p { margin: 0; color: var(--wrn-color-muted); }
|
||||
.wrn-next--rating > .wrn-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.wrn-next--rating > .wrn-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wrn-radius-sm); background: var(--wrn-color-surface-2); }
|
||||
|
||||
/* 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;
|
||||
}
|
||||
.wrn-rating__precise { position:absolute; opacity:0; width:1px; height:1px; }
|
||||
.wrn-rating__precise:focus-visible { position:static; opacity:1; width:5rem; height:auto; accent-color:var(--wrn-color-primary); }
|
||||
.wrn-rating { display:grid; gap:.6rem; color:var(--wrn-color-text); }
|
||||
.wrn-rating p { margin:0; color:var(--wrn-color-muted); font-size:.875rem; }
|
||||
.wrn-rating__stars { display:flex; align-items:center; gap:.25rem; }
|
||||
.wrn-rating button { display:grid; place-items:center; width:2rem; height:2rem; padding:.2rem; border:0; background:transparent; color:var(--wrn-color-muted); cursor:pointer; }
|
||||
.wrn-rating svg { width:1.5rem; height:1.5rem; fill:none; stroke:currentColor; stroke-width:1.5; }
|
||||
.wrn-rating button[data-filled="true"] { color:var(--wrn-color-warning-text); }
|
||||
.wrn-rating svg { grid-area:1 / 1; }
|
||||
.wrn-rating .wrn-rating__fill { fill:currentColor; clip-path:inset(0 calc(100% - var(--fill)) 0 0); }
|
||||
.wrn-rating output { margin-inline-start:.5rem; font-size:.8rem; color:var(--wrn-color-muted); }
|
||||
.wrn-rating button:focus-visible { outline:2px solid var(--wrn-color-focus); outline-offset:2px; border-radius:4px; }
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,7 @@ component SearchBox {
|
||||
}
|
||||
|
||||
style {
|
||||
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance:none; appearance:none; }
|
||||
.wrn-search-box { width: 100%; }
|
||||
.wrn-search-box__label {
|
||||
display: block;
|
||||
|
||||
@@ -50,7 +50,7 @@ component SectionHeader {
|
||||
style {
|
||||
.wrn-section-header {
|
||||
--section-header-accent: var(--wrn-color-primary);
|
||||
--section-header-title: 1.875rem;
|
||||
--section-header-title: 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
@@ -131,7 +131,7 @@ component SectionHeader {
|
||||
color: var(--section-header-accent);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.18em;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@@ -149,9 +149,9 @@ component SectionHeader {
|
||||
}
|
||||
|
||||
.wrn-section-header__description {
|
||||
margin: 1rem 0 0;
|
||||
margin: 0.5rem 0 0;
|
||||
color: var(--wrn-color-text-muted);
|
||||
font-size: 1rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
@@ -185,24 +185,24 @@ component SectionHeader {
|
||||
* split only becomes a row once there is width for two columns.
|
||||
*/
|
||||
.wrn-section-header[data-size="sm"] {
|
||||
--section-header-title: 1.5rem;
|
||||
--section-header-title: 1.125rem;
|
||||
}
|
||||
|
||||
.wrn-section-header[data-size="lg"] {
|
||||
--section-header-title: 2.25rem;
|
||||
--section-header-title: 1.5rem;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.wrn-section-header {
|
||||
--section-header-title: 2.25rem;
|
||||
--section-header-title: 1.25rem;
|
||||
}
|
||||
|
||||
.wrn-section-header[data-size="sm"] {
|
||||
--section-header-title: 1.75rem;
|
||||
--section-header-title: 1.125rem;
|
||||
}
|
||||
|
||||
.wrn-section-header[data-size="lg"] {
|
||||
--section-header-title: 3rem;
|
||||
--section-header-title: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ component Stepper {
|
||||
size: string = "default"
|
||||
steps: unknown[] = []
|
||||
active: number = 0
|
||||
controlled: boolean = false
|
||||
orientation: string = "horizontal"
|
||||
clickable: boolean = false
|
||||
label: string = "Progress"
|
||||
@@ -44,6 +45,8 @@ component Stepper {
|
||||
class: string = ""
|
||||
}
|
||||
|
||||
state currentStep = active
|
||||
|
||||
functions {
|
||||
shared function stepList() {
|
||||
return Array.isArray(steps) ? steps : []
|
||||
@@ -54,7 +57,7 @@ component Stepper {
|
||||
if (count < 1) {
|
||||
return 0
|
||||
}
|
||||
var value = Number(active)
|
||||
var value = Number(controlled ? active : currentStep)
|
||||
if (!value || value < 0) {
|
||||
return 0
|
||||
}
|
||||
@@ -100,6 +103,7 @@ component Stepper {
|
||||
client function goBack() {
|
||||
var target = Math.max(0, activeIndex() - 1)
|
||||
output.back({ index: target, step: stepList()[target] || {} })
|
||||
currentStep = target
|
||||
output.change({ index: target, step: stepList()[target] || {} })
|
||||
}
|
||||
|
||||
@@ -113,12 +117,14 @@ component Stepper {
|
||||
}
|
||||
var target = Math.min(lastIndex(), activeIndex() + 1)
|
||||
output.next({ index: target, step: stepList()[target] || {} })
|
||||
currentStep = target
|
||||
output.change({ index: target, step: stepList()[target] || {} })
|
||||
}
|
||||
|
||||
client function goSkip() {
|
||||
var target = Math.min(lastIndex(), activeIndex() + 1)
|
||||
output.skip({ index: target, step: stepList()[target] || {} })
|
||||
currentStep = target
|
||||
output.change({ index: target, step: stepList()[target] || {} })
|
||||
}
|
||||
|
||||
@@ -126,6 +132,7 @@ component Stepper {
|
||||
if (!clickable) {
|
||||
return
|
||||
}
|
||||
currentStep = index
|
||||
output.change({ index: index, step: step })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,11 +408,14 @@ component StrongPassword {
|
||||
|
||||
.wrn-next__strong-password-requirements .wrn-next__strong-password-special {
|
||||
grid-column: 1 / -1;
|
||||
white-space: nowrap;
|
||||
white-space: normal;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.wrn-next__strong-password-special [data-text="specialCharactersSet"] {
|
||||
white-space: nowrap;
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wrn-next__strong-password-requirements li > span[aria-hidden="true"] {
|
||||
@@ -462,7 +465,7 @@ component StrongPassword {
|
||||
top: calc(100% + 0.7rem);
|
||||
left: 0;
|
||||
z-index: 30;
|
||||
width: min(28rem, calc(100vw - 2rem));
|
||||
width: min(28rem, 100%);
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius);
|
||||
@@ -607,10 +610,10 @@ component StrongPassword {
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -624,9 +627,9 @@ component StrongPassword {
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -668,7 +671,7 @@ component StrongPassword {
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -682,10 +685,10 @@ component StrongPassword {
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -793,7 +796,7 @@ component StrongPassword {
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -802,7 +805,7 @@ component StrongPassword {
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -951,7 +954,7 @@ component StrongPassword {
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -6,98 +6,23 @@ component StyledIcon {
|
||||
description: string = ""
|
||||
items: unknown[] = []
|
||||
variant: string = "default"
|
||||
icon: string = "icon-[lucide--sparkles]"
|
||||
label: string = ""
|
||||
class: string = ""
|
||||
}
|
||||
|
||||
view {
|
||||
<section class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--styled-icon wrn-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wrn-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
</section>
|
||||
<span {...attrs} class="wrn-styled-icon {class}" data-size="{size}" data-color="{color}" data-variant="{variant}" role="{label ? 'img' : 'presentation'}" aria-label="{label}" aria-hidden="{label ? 'false' : 'true'}"><span class="{icon}"></span></span>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next--styled-icon {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius);
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface);
|
||||
}
|
||||
.wrn-next--styled-icon > p { margin: 0; color: var(--wrn-color-muted); }
|
||||
.wrn-next--styled-icon > .wrn-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.wrn-next--styled-icon > .wrn-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wrn-radius-sm); background: var(--wrn-color-surface-2); }
|
||||
|
||||
/* 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;
|
||||
}
|
||||
.wrn-styled-icon { --icon-color:var(--wrn-color-primary-text); display:inline-grid; place-items:center; width:2.5rem; height:2.5rem; border-radius:var(--wrn-radius-sm); color:var(--icon-color); background:color-mix(in srgb, var(--icon-color) 12%, transparent); }
|
||||
.wrn-styled-icon > span { width:1.25rem; height:1.25rem; }
|
||||
.wrn-styled-icon[data-color="success"] { --icon-color:var(--wrn-color-success-text); }
|
||||
.wrn-styled-icon[data-color="warning"] { --icon-color:var(--wrn-color-warning-text); }
|
||||
.wrn-styled-icon[data-size="sm"] { width:2rem; height:2rem; }
|
||||
.wrn-styled-icon[data-size="lg"] { width:3rem; height:3rem; }
|
||||
.wrn-styled-icon[data-variant="outline"] { border:1px solid currentColor; background:transparent; }
|
||||
.wrn-styled-icon[data-variant="plain"] { background:transparent; }
|
||||
}
|
||||
}
|
||||
@@ -44,27 +44,28 @@ size: string = "default"
|
||||
functions {
|
||||
client function commit(part, nextValue, sourceEvent, next, detail) { if (part === "hour") { selectedHour = String(nextValue).padStart(2, "0") } if (part === "minute") { selectedMinute = String(nextValue).padStart(2, "0") } next = selectedHour + ":" + selectedMinute; if ((min && next < min) || (max && next > max)) { return } currentValue = next; detail = { value: currentValue, hour: selectedHour, minute: selectedMinute, name: name, sourceEvent: sourceEvent }; output.input(detail); output.change(detail) }
|
||||
client function selectTimePart(sourceEvent, root, input, parts, hourValue, minuteValue, next, trigger, detail) { root = sourceEvent.currentTarget.closest(".wrn-next--time-picker"); input = root.querySelector(".wrn-next__time-value"); parts = String(input.value || value || "00:00").split(":"); hourValue = sourceEvent.currentTarget.dataset.part === "hour" ? sourceEvent.currentTarget.dataset.value : parts[0]; minuteValue = sourceEvent.currentTarget.dataset.part === "minute" ? sourceEvent.currentTarget.dataset.value : parts[1]; next = hourValue + ":" + minuteValue; if ((min && next < min) || (max && next > max)) { return } currentValue = next; input.setAttribute("value", next); trigger = root.querySelector(".wrn-next__time-trigger span"); if (trigger) { trigger.replaceChildren(next) } sourceEvent.currentTarget.setAttribute("aria-pressed", "true"); detail = { value: next, hour: hourValue, minute: minuteValue, name: name, sourceEvent: sourceEvent }; output.input(detail); output.change(detail) }
|
||||
client function openPicker(sourceEvent) { expanded = true; output.open({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function openPicker(sourceEvent) { expanded = !expanded; output.open({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function closePicker(sourceEvent) { expanded = false; output.close({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function handleFocus(sourceEvent) { output.focus({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function handleBlur(sourceEvent) { output.blur({ value: currentValue, name: name, sourceEvent: sourceEvent }) }
|
||||
client function handleInvalid(sourceEvent) { output.invalid({ name: name, message: sourceEvent.currentTarget.validationMessage, sourceEvent: sourceEvent }) }
|
||||
}
|
||||
view {
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--time-picker {class}" data-variant="{variant}" data-inline="{inline}" data-floating="{variant === 'floating'}" data-invalid="{error ? 'true' : 'false'}" data-expanded="{expanded}">
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--time-picker {class}" data-variant="{variant}" data-inline="{inline}" data-floating="{variant === 'floating'}" data-invalid="{error ? 'true' : 'false'}" data-expanded="{expanded}" @keydown="if (event.key === 'Escape') { closePicker(event) }">
|
||||
<div class="wrn-next__field-heading"><label class="{hiddenLabel ? 'wrn-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wrn-next__field-hint">{cornerHint}</span>{/if}</div>
|
||||
<div class="wrn-next__field-control" data-icon-position="{iconPosition}">
|
||||
{#if icon}<span class="{icon} wrn-next__field-icon" aria-hidden="true"></span>{/if}
|
||||
<input id="{id || name}" class="wrn-next__sr-only wrn-next__time-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" />
|
||||
<button type="button" class="wrn-next__time-trigger" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openPicker(event)" @focus="handleFocus(event)" @blur="handleBlur(event)"><span>{currentValue || placeholder || "Select time"}</span><i class="{icon}" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
<div class="wrn-next__time-panel" role="dialog" aria-label="{label}"><div><strong>Hour</strong><div class="wrn-next__time-options">{#each hours as hour}<button type="button" data-part="hour" data-value="{hour}" aria-pressed="{String(hour) === selectedHour}" @click="selectTimePart(event)">{hour}</button>{/each}</div></div><div><strong>Minute</strong><div class="wrn-next__time-options">{#each minutes as minute}<button type="button" data-part="minute" data-value="{minute}" aria-pressed="{String(minute) === selectedMinute}" @click="selectTimePart(event)">{minute}</button>{/each}</div></div><button type="button" class="wrn-next__time-done" @click="closePicker(event)">Done</button></div>
|
||||
<button type="button" class="wrn-time-dismiss" aria-label="Close time picker" data-show="expanded" @click="closePicker(event)"></button><div data-show="expanded" class="wrn-next__time-panel" role="dialog" aria-label="{label}"><div><strong>Hour</strong><div class="wrn-next__time-options">{#each hours as hour}<button type="button" data-part="hour" data-value="{hour}" aria-pressed="{String(hour) === selectedHour}" @click="selectTimePart(event)">{hour}</button>{/each}</div></div><div><strong>Minute</strong><div class="wrn-next__time-options">{#each minutes as minute}<button type="button" data-part="minute" data-value="{minute}" aria-pressed="{String(minute) === selectedMinute}" @click="selectTimePart(event)">{minute}</button>{/each}</div></div><button type="button" class="wrn-next__time-done" @click="closePicker(event)">Done</button></div>
|
||||
{#if helperText}<small class="wrn-next__field-help">{helperText}</small>{/if}
|
||||
<small class="wrn-next__field-error" data-error="{name}">{error}</small>
|
||||
</div>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-time-dismiss { position:fixed; inset:0; z-index:39; opacity:0; border:0; }
|
||||
.wrn-next__time-panel {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
@@ -195,10 +196,10 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -212,9 +213,9 @@ size: string = "default"
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -256,7 +257,7 @@ size: string = "default"
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -270,10 +271,10 @@ size: string = "default"
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -381,7 +382,7 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -390,7 +391,7 @@ size: string = "default"
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -539,7 +540,7 @@ size: string = "default"
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
@@ -551,9 +552,13 @@ size: string = "default"
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
.wrn-next--date-picker, .wrn-next--time-picker { position: relative; }
|
||||
.wrn-next__calendar,
|
||||
.wrn-next__time-panel {
|
||||
z-index: 20;
|
||||
position: absolute;
|
||||
inset-block-start: calc(100% + .4rem);
|
||||
inset-inline-start: 0;
|
||||
z-index: 40;
|
||||
display: grid;
|
||||
width: min(100%, 22rem);
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -659,7 +659,7 @@ component Toaster {
|
||||
}
|
||||
|
||||
.wrn-toaster[data-size="sm"] .wrn-toast {
|
||||
padding: 0.6rem 0.7rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ component ToggleCount {
|
||||
|
||||
}
|
||||
|
||||
state selectedValue = value
|
||||
state selectedValue = value === secondValue ? secondValue : firstValue
|
||||
|
||||
functions {
|
||||
shared function isFirstSelected() {
|
||||
|
||||
@@ -9,6 +9,7 @@ component TogglePassword {
|
||||
size: string = "default"
|
||||
color: string = "primary"
|
||||
label: string = "Password"
|
||||
icon: string = ""
|
||||
name: string = "password"
|
||||
value: string = ""
|
||||
placeholder: string = "Enter your password"
|
||||
@@ -116,7 +117,7 @@ component TogglePassword {
|
||||
{/if}
|
||||
</div>
|
||||
<div class="wrn-next__password-control">
|
||||
<span class="wrn-next__password-leading-icon" aria-hidden="true"></span>
|
||||
{#if icon}<span class="wrn-next__password-leading-icon {icon}" aria-hidden="true"></span>{/if}
|
||||
<input
|
||||
{...attrs}
|
||||
id="{name}-password"
|
||||
@@ -203,7 +204,7 @@ component TogglePassword {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wrn-next__password-heading :is(a, span) {
|
||||
.wrn-next__password-heading > :is(a, span) {
|
||||
color: var(--wrn-component-color);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
@@ -241,9 +242,8 @@ component TogglePassword {
|
||||
.wrn-next__password-control > input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 2.75em;
|
||||
min-height: 3rem;
|
||||
padding: 0.75rem 3rem 0.75rem 2.75rem;
|
||||
min-height: var(--wrn-control-height);
|
||||
padding: 0.55rem 3rem 0.55rem 0.85rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius-sm);
|
||||
outline: 0;
|
||||
@@ -265,8 +265,8 @@ component TogglePassword {
|
||||
color: var(--wrn-color-muted);
|
||||
background: currentColor;
|
||||
pointer-events: none;
|
||||
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='11' x='3' y='11' rx='2' ry='2'/%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'/%3E%3C/svg%3E") center / contain no-repeat;
|
||||
}
|
||||
.wrn-next__password-control:has(> .wrn-next__password-leading-icon) > input { padding-inline-start: 2.5rem; }
|
||||
|
||||
.wrn-next__password-control > input:focus-visible {
|
||||
border-color: var(--wrn-component-color);
|
||||
@@ -450,10 +450,10 @@ component TogglePassword {
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -467,9 +467,9 @@ component TogglePassword {
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -511,7 +511,7 @@ component TogglePassword {
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -525,10 +525,10 @@ component TogglePassword {
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -636,7 +636,7 @@ component TogglePassword {
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -645,7 +645,7 @@ component TogglePassword {
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -794,7 +794,7 @@ component TogglePassword {
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
component WysiwygEditor {
|
||||
// A chrome shell around a slotted editor, not an editor itself: it renders a
|
||||
// heading, a description, an optional item strip and a slot. It therefore
|
||||
// emits none of these outputs on its own -- they forward whatever the slotted
|
||||
// control raises. Slot a textarea or input and a parent @change or @input
|
||||
// hears it, because those events bubble to this root; @focus and @blur arrive
|
||||
// too, since the runtime binds the non-bubbling pair in the capture phase.
|
||||
// Slot nothing interactive and there is nothing to hear.
|
||||
outputs {
|
||||
input(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)
|
||||
change(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)
|
||||
@@ -20,98 +13,48 @@ component WysiwygEditor {
|
||||
description: string = ""
|
||||
items: unknown[] = []
|
||||
variant: string = "default"
|
||||
value: string = ""
|
||||
readonly: boolean = false
|
||||
placeholder: string = "Write something…"
|
||||
class: string = ""
|
||||
}
|
||||
functions {
|
||||
client function format(command, sourceEvent, root, editor) {
|
||||
sourceEvent.preventDefault()
|
||||
root = sourceEvent.currentTarget.closest(".wrn-editor")
|
||||
editor = root.querySelector("[contenteditable]")
|
||||
editor.focus()
|
||||
document.execCommand(command, false, null)
|
||||
output.input({ value: editor.innerHTML, text: editor.textContent })
|
||||
output.change({ value: editor.innerHTML, text: editor.textContent })
|
||||
}
|
||||
client function edit(sourceEvent) { output.input({ value: sourceEvent.currentTarget.innerHTML, text: sourceEvent.currentTarget.textContent }) }
|
||||
client function finish(sourceEvent) { output.change({ value: sourceEvent.currentTarget.innerHTML, text: sourceEvent.currentTarget.textContent }); output.blur({ sourceEvent: sourceEvent }) }
|
||||
}
|
||||
view {
|
||||
<section class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--wysiwyg-editor wrn-next--variant-{variant} {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}
|
||||
{#if description}<p>{description}</p>{/if}
|
||||
{#if items}<div class="wrn-next__items">{#each items as item}<span>{item.label}</span>{/each}</div>{/if}
|
||||
<slot />
|
||||
<section {...attrs} class="wrn-editor {class}">
|
||||
{#if title}<strong>{title}</strong>{/if}{#if description}<p>{description}</p>{/if}
|
||||
<div class="wrn-editor__surface">
|
||||
<div role="toolbar" aria-label="Text formatting" class="wrn-editor__toolbar">
|
||||
<button type="button" disabled="{readonly}" aria-label="Bold" @mousedown="event.preventDefault()" @click="format('bold', event)"><strong>B</strong></button>
|
||||
<button type="button" disabled="{readonly}" aria-label="Italic" @mousedown="event.preventDefault()" @click="format('italic', event)"><em>I</em></button>
|
||||
<button type="button" disabled="{readonly}" aria-label="Underline" @mousedown="event.preventDefault()" @click="format('underline', event)"><u>U</u></button>
|
||||
<button type="button" disabled="{readonly}" aria-label="Bulleted list" @mousedown="event.preventDefault()" @click="format('insertUnorderedList', event)"><span class="icon-[lucide--list]" aria-hidden="true"></span></button>
|
||||
<button type="button" disabled="{readonly}" aria-label="Undo" @mousedown="event.preventDefault()" @click="format('undo', event)"><span class="icon-[lucide--undo-2]" aria-hidden="true"></span></button>
|
||||
<button type="button" disabled="{readonly}" aria-label="Strike through" @mousedown="event.preventDefault()" @click="format('strikeThrough', event)">S̶</button><button type="button" disabled="{readonly}" aria-label="Numbered list" @mousedown="event.preventDefault()" @click="format('insertOrderedList', event)">1.</button><button type="button" disabled="{readonly}" aria-label="Align left" @mousedown="event.preventDefault()" @click="format('justifyLeft', event)">⇤</button><button type="button" disabled="{readonly}" aria-label="Align center" @mousedown="event.preventDefault()" @click="format('justifyCenter', event)">↔</button><button type="button" disabled="{readonly}" aria-label="Align right" @mousedown="event.preventDefault()" @click="format('justifyRight', event)">⇥</button><button type="button" disabled="{readonly}" aria-label="Indent" @mousedown="event.preventDefault()" @click="format('indent', event)">→</button><button type="button" disabled="{readonly}" aria-label="Outdent" @mousedown="event.preventDefault()" @click="format('outdent', event)">←</button><button type="button" disabled="{readonly}" aria-label="Remove formatting" @mousedown="event.preventDefault()" @click="format('removeFormat', event)">Tx</button><button type="button" disabled="{readonly}" aria-label="Redo" @mousedown="event.preventDefault()" @click="format('redo', event)">↻</button> </div>
|
||||
<div contenteditable="{readonly ? 'false' : 'true'}" role="textbox" aria-label="{title || 'Rich text editor'}" aria-multiline="true" aria-readonly="{readonly}" data-placeholder="{placeholder}" class="wrn-editor__content" @input="edit(event)" @blur="finish(event)" @focus="output.focus({ sourceEvent: event })">{value}</div>
|
||||
</div><slot />
|
||||
</section>
|
||||
}
|
||||
|
||||
style {
|
||||
.wrn-next--wysiwyg-editor {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: var(--wrn-radius);
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-surface);
|
||||
}
|
||||
.wrn-next--wysiwyg-editor > p { margin: 0; color: var(--wrn-color-muted); }
|
||||
.wrn-next--wysiwyg-editor > .wrn-next__items { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.wrn-next--wysiwyg-editor > .wrn-next__items > span { padding: 0.35rem 0.6rem; border-radius: var(--wrn-radius-sm); background: var(--wrn-color-surface-2); }
|
||||
|
||||
/* 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;
|
||||
}
|
||||
.wrn-editor { display:grid; gap:.65rem; color:var(--wrn-color-text); }
|
||||
.wrn-editor > p { margin:0; color:var(--wrn-color-muted); font-size:.875rem; }
|
||||
.wrn-editor__surface { border:1px solid var(--wrn-color-border); border-radius:var(--wrn-radius-md); overflow:hidden; background:var(--wrn-color-surface); }
|
||||
.wrn-editor__toolbar { display:flex; flex-wrap:wrap; gap:.25rem; padding:.4rem; border-bottom:1px solid var(--wrn-color-border); }
|
||||
.wrn-editor button { display:grid; place-items:center; width:2rem; height:2rem; border:0; border-radius:4px; background:transparent; color:inherit; cursor:pointer; }
|
||||
.wrn-editor button:hover { background:var(--wrn-color-surface-2); }
|
||||
.wrn-editor button span { width:1rem; height:1rem; }
|
||||
.wrn-editor__content { min-height:10rem; padding:1rem; outline-offset:-2px; font-size:.875rem; line-height:1.65; }
|
||||
.wrn-editor__content:empty::before { content:attr(data-placeholder); color:var(--wrn-color-muted); pointer-events:none; }
|
||||
}
|
||||
}
|
||||
@@ -152,10 +152,10 @@ component Alert {
|
||||
.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);
|
||||
color: var(--wrn-alert-ink, var(--wrn-color-primary-text));
|
||||
}
|
||||
.wrn-next--alert-solid {
|
||||
border-color: var(--wrn-alert-color);
|
||||
border-color: var(--wrn-alert-ink, var(--wrn-color-primary-text));
|
||||
background: var(--wrn-alert-color);
|
||||
color: white;
|
||||
}
|
||||
@@ -176,13 +176,13 @@ component Alert {
|
||||
color: #18181b;
|
||||
}
|
||||
.wrn-next--alert-bordered {
|
||||
border-color: var(--wrn-alert-color);
|
||||
border-color: var(--wrn-alert-ink, var(--wrn-color-primary-text));
|
||||
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);
|
||||
color: var(--wrn-alert-ink, var(--wrn-color-primary-text));
|
||||
}
|
||||
.wrn-next--alert-accent {
|
||||
border-color: color-mix(in srgb, var(--wrn-alert-color) 35%, var(--wrn-color-border));
|
||||
@@ -192,7 +192,7 @@ component Alert {
|
||||
.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);
|
||||
color: var(--wrn-alert-ink, var(--wrn-color-primary-text));
|
||||
}
|
||||
|
||||
.wrn-next--alert {
|
||||
@@ -249,19 +249,23 @@ component Alert {
|
||||
}
|
||||
|
||||
.wrn-next--alert[data-color="success"] {
|
||||
--wrn-alert-color: #0f9f8f;
|
||||
--wrn-alert-color: var(--wrn-color-success);
|
||||
--wrn-alert-ink: var(--wrn-color-success-text);
|
||||
}
|
||||
|
||||
.wrn-next--alert[data-color="danger"] {
|
||||
--wrn-alert-color: #dc3545;
|
||||
--wrn-alert-color: var(--wrn-color-danger);
|
||||
--wrn-alert-ink: var(--wrn-color-danger-text);
|
||||
}
|
||||
|
||||
.wrn-next--alert[data-color="warning"] {
|
||||
--wrn-alert-color: #eab308;
|
||||
--wrn-alert-color: var(--wrn-color-warning);
|
||||
--wrn-alert-ink: var(--wrn-color-warning-text);
|
||||
}
|
||||
|
||||
.wrn-next--alert[data-color="info"] {
|
||||
--wrn-alert-color: #2563eb;
|
||||
--wrn-alert-color: var(--wrn-color-info);
|
||||
--wrn-alert-ink: var(--wrn-color-info-text);
|
||||
}
|
||||
|
||||
.wrn-next--alert[data-color="dark"] {
|
||||
@@ -298,7 +302,7 @@ component Alert {
|
||||
height: 1.25rem;
|
||||
place-items: center;
|
||||
margin-top: 0.05rem;
|
||||
color: var(--wrn-alert-color);
|
||||
color: var(--wrn-alert-ink, var(--wrn-color-primary-text));
|
||||
}
|
||||
|
||||
.wrn-next__alert-icon > span {
|
||||
@@ -339,7 +343,7 @@ component Alert {
|
||||
}
|
||||
|
||||
.wrn-next__alert-actions a {
|
||||
color: var(--wrn-alert-color);
|
||||
color: var(--wrn-alert-ink, var(--wrn-color-primary-text));
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
|
||||
@@ -122,6 +122,7 @@ component Badge {
|
||||
|
||||
.wrn-next__badge {
|
||||
--wrn-badge-color: var(--wrn-color-primary);
|
||||
--wrn-badge-ink: var(--wrn-color-primary-text);
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
display: inline-flex;
|
||||
@@ -136,9 +137,9 @@ component Badge {
|
||||
border: 1px solid var(--wrn-badge-color);
|
||||
border-radius: 999px;
|
||||
background: var(--wrn-badge-color);
|
||||
box-shadow: 0 4px 12px color-mix(in srgb, var(--wrn-badge-color) 18%, transparent);
|
||||
box-shadow: none;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 750;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -166,23 +167,28 @@ component Badge {
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-color="secondary"] {
|
||||
--wrn-badge-color: #737373;
|
||||
--wrn-badge-color: var(--wrn-color-secondary);
|
||||
--wrn-badge-ink: var(--wrn-color-secondary-text);
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-color="success"] {
|
||||
--wrn-badge-color: #0f9f8f;
|
||||
--wrn-badge-color: var(--wrn-color-success);
|
||||
--wrn-badge-ink: var(--wrn-color-success-text);
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-color="info"] {
|
||||
--wrn-badge-color: #2563eb;
|
||||
--wrn-badge-color: var(--wrn-color-info);
|
||||
--wrn-badge-ink: var(--wrn-color-info-text);
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-color="danger"] {
|
||||
--wrn-badge-color: #ef3340;
|
||||
--wrn-badge-color: var(--wrn-color-danger);
|
||||
--wrn-badge-ink: var(--wrn-color-danger-text);
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-color="warning"] {
|
||||
--wrn-badge-color: #eab308;
|
||||
--wrn-badge-color: var(--wrn-color-warning);
|
||||
--wrn-badge-ink: var(--wrn-color-warning-text);
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-color="dark"] {
|
||||
@@ -199,14 +205,14 @@ component Badge {
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-variant="soft"] {
|
||||
color: var(--wrn-badge-color);
|
||||
color: var(--wrn-badge-ink, var(--wrn-badge-color));
|
||||
border-color: transparent;
|
||||
background: color-mix(in srgb, var(--wrn-badge-color) 15%, var(--wrn-color-surface));
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-variant="outline"] {
|
||||
color: var(--wrn-badge-color);
|
||||
color: var(--wrn-badge-ink, var(--wrn-badge-color));
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ label: string = "Button"
|
||||
padding: 0 0.75rem;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
min-height: 2rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
transition:
|
||||
color var(--wrn-motion-base) var(--wrn-ease-standard),
|
||||
border-color var(--wrn-motion-base) var(--wrn-ease-standard),
|
||||
@@ -256,9 +256,7 @@ label: string = "Button"
|
||||
.wrn-btn--primary {
|
||||
color: var(--wrn-btn-contrast);
|
||||
background: var(--wrn-btn-color);
|
||||
box-shadow:
|
||||
0 1px 2px color-mix(in srgb, black 20%, transparent),
|
||||
0 0 0 1px color-mix(in srgb, var(--wrn-btn-color) 72%, transparent);
|
||||
box-shadow: var(--wrn-shadow-sm);
|
||||
}
|
||||
.wrn-btn--variant-default:hover,
|
||||
.wrn-btn--variant-solid:hover,
|
||||
@@ -266,10 +264,7 @@ label: string = "Button"
|
||||
.wrn-btn--solid:hover,
|
||||
.wrn-btn--primary:hover {
|
||||
background: color-mix(in srgb, var(--wrn-btn-color) 84%, black);
|
||||
transform: translateY(-1px);
|
||||
box-shadow:
|
||||
0 0.35rem 0.9rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent),
|
||||
0 0 0 1px color-mix(in srgb, var(--wrn-btn-color) 82%, transparent);
|
||||
box-shadow: var(--wrn-shadow-sm);
|
||||
}
|
||||
.wrn-btn--variant-outline,
|
||||
.wrn-btn--outline {
|
||||
@@ -319,7 +314,7 @@ label: string = "Button"
|
||||
color: var(--wrn-btn-color);
|
||||
border-color: color-mix(in srgb, var(--wrn-btn-color) 55%, var(--wrn-color-border));
|
||||
background: color-mix(in srgb, var(--wrn-btn-color) 15%, var(--wrn-color-surface));
|
||||
transform: translateY(-2px);
|
||||
transform: none;
|
||||
}
|
||||
.wrn-btn--variant-link,
|
||||
.wrn-btn--link {
|
||||
@@ -351,20 +346,20 @@ label: string = "Button"
|
||||
}
|
||||
.wrn-btn--size-sm,
|
||||
.wrn-btn--sm {
|
||||
min-height: 2.125rem;
|
||||
min-height: var(--wrn-control-height-sm, 2rem);
|
||||
padding-inline: 0.625rem;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.wrn-btn--size-default,
|
||||
.wrn-btn--md {
|
||||
min-height: 2.5rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding-inline: 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.wrn-btn--size-lg,
|
||||
.wrn-btn--lg {
|
||||
min-height: 2.75rem;
|
||||
min-height: var(--wrn-control-height-lg, 2.75rem);
|
||||
padding-inline: 0.875rem;
|
||||
font-size: 0.925rem;
|
||||
}
|
||||
|
||||
@@ -306,10 +306,10 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -323,9 +323,9 @@ size: string = "default"
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -367,7 +367,7 @@ size: string = "default"
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -381,10 +381,10 @@ size: string = "default"
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -492,7 +492,7 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -501,7 +501,7 @@ size: string = "default"
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -650,7 +650,7 @@ size: string = "default"
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -274,10 +274,10 @@ component Input {
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -291,9 +291,9 @@ component Input {
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -341,7 +341,7 @@ component Input {
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -489,7 +489,7 @@ component Input {
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -498,7 +498,7 @@ component Input {
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -647,7 +647,7 @@ component Input {
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -167,10 +167,10 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -184,9 +184,9 @@ size: string = "default"
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -228,7 +228,7 @@ size: string = "default"
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -242,10 +242,10 @@ size: string = "default"
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -353,7 +353,7 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -362,7 +362,7 @@ size: string = "default"
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -511,7 +511,7 @@ size: string = "default"
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -51,7 +51,7 @@ size: string = "default"
|
||||
view {
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--select {class}" data-variant="{variant}" data-inline="{inline}" data-floating="{variant === 'floating'}" data-invalid="{error || validationError ? 'true' : 'false'}" data-readonly="{readonly}">
|
||||
<div class="wrn-next__field-heading"><label class="{hiddenLabel ? 'wrn-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wrn-next__field-hint">{cornerHint}</span>{/if}</div>
|
||||
<div class="wrn-next__field-control" data-icon-position="{iconPosition}">
|
||||
<div class="wrn-next__field-control" data-icon-position="{iconPosition}" data-has-icon="{icon ? 'true' : 'false'}">
|
||||
{#if icon}<span class="{icon} wrn-next__field-icon" aria-hidden="true"></span>{/if}
|
||||
<select id="{id || name}" name="{name}" multiple="{multiple}" disabled="{disabled || readonly}" required="{required}" aria-readonly="{readonly}" aria-invalid="{error || validationError ? 'true' : 'false'}" aria-describedby="{error || validationError ? (id || name) + '-error' : (helperText ? (id || name) + '-help' : '')}" @input="emitField('input', event)" @change="emitField('change', event)" @focus="handleFocus(event)" @blur="handleBlur(event)" @invalid="handleInvalid(event)">
|
||||
{#if !multiple}<option value="" selected="{value === ''}" disabled="{required}">{placeholder}</option>{/if}
|
||||
@@ -69,7 +69,7 @@ size: string = "default"
|
||||
.wrn-next--select select {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
margin: 0;
|
||||
padding-inline-end: 2.5rem;
|
||||
line-height: 1.35;
|
||||
@@ -194,10 +194,10 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -211,9 +211,9 @@ size: string = "default"
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -255,7 +255,7 @@ size: string = "default"
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -269,10 +269,10 @@ size: string = "default"
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -380,7 +380,7 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -389,7 +389,7 @@ size: string = "default"
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -538,7 +538,7 @@ size: string = "default"
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -28,14 +28,15 @@ component Switch {
|
||||
required: boolean = false
|
||||
class: string = ""
|
||||
}
|
||||
state currentChecked = checked
|
||||
functions {
|
||||
client function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); output[nameEvent]({ checked: sourceEvent.currentTarget.checked, value: value, name: name, sourceEvent: sourceEvent }) }
|
||||
client function emitField(nameEvent, sourceEvent) { sourceEvent.stopPropagation(); currentChecked = sourceEvent.currentTarget.checked; output[nameEvent]({ checked: sourceEvent.currentTarget.checked, value: value, name: name, sourceEvent: sourceEvent }) }
|
||||
client function preventReadonly(sourceEvent) { if (readonly) sourceEvent.preventDefault() }
|
||||
}
|
||||
view {
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--choice-field {class}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}">
|
||||
<div class="wrn-next__field-heading">{#if cornerHint}<span class="{hiddenLabel ? 'wrn-next__sr-only' : ''}">{label}</span><span class="wrn-next__field-hint">{cornerHint}</span>{/if}</div>
|
||||
<label class="wrn-next__choice wrn-next--switch" for="{id || name}" data-variant="{variant}" data-icon-position="{iconPosition}"><input id="{id || name}" type="checkbox" role="switch" name="{name}" value="{value}" checked="{checked}" disabled="{disabled}" required="{required}" readonly="{readonly}" aria-checked="{checked ? 'true' : 'false'}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" />{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}<span class="{hiddenLabel || cornerHint ? 'wrn-next__sr-only' : ''}">{label}</span></label>
|
||||
<label class="wrn-next__choice wrn-next--switch" data-variant="{variant}" data-icon-position="{iconPosition}"><input id="{id || name}" type="checkbox" role="switch" name="{name}" value="{value}" checked="{currentChecked}" disabled="{disabled}" required="{required}" readonly="{readonly}" aria-checked="{currentChecked ? 'true' : 'false'}" aria-invalid="{error ? 'true' : 'false'}" @click="preventReadonly(event)" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" />{#if icon}<span class="{icon}" aria-hidden="true"></span>{/if}<span class="{hiddenLabel || cornerHint ? 'wrn-next__sr-only' : ''}">{label}</span></label>
|
||||
{#if helperText}<small class="wrn-next__field-help">{helperText}</small>{/if}<small class="wrn-next__field-error" data-error="{name}">{error}</small>
|
||||
</div>
|
||||
}
|
||||
@@ -53,7 +54,7 @@ component Switch {
|
||||
}
|
||||
|
||||
.wrn-next--switch {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
@@ -189,10 +190,10 @@ component Switch {
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -206,9 +207,9 @@ component Switch {
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -250,7 +251,7 @@ component Switch {
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -264,10 +265,10 @@ component Switch {
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -375,7 +376,7 @@ component Switch {
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -384,7 +385,7 @@ component Switch {
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -533,7 +534,7 @@ component Switch {
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
@@ -51,7 +51,7 @@ size: string = "default"
|
||||
view {
|
||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--textarea {class}" data-variant="{variant}" data-inline="{inline}" data-floating="{variant === 'floating'}" data-invalid="{error || validationError ? 'true' : 'false'}">
|
||||
<div class="wrn-next__field-heading"><label class="{hiddenLabel ? 'wrn-next__sr-only' : ''}" for="{id || name}">{label}</label>{#if cornerHint}<span class="wrn-next__field-hint">{cornerHint}</span>{/if}</div>
|
||||
<div class="wrn-next__field-control" data-icon-position="{iconPosition}">
|
||||
<div class="wrn-next__field-control" data-icon-position="{iconPosition}" data-has-icon="{icon ? 'true' : 'false'}">
|
||||
{#if icon}<span class="{icon} wrn-next__field-icon" aria-hidden="true"></span>{/if}
|
||||
<textarea id="{id || name}" name="{name}" value="{value}" placeholder="{variant === 'floating' ? ' ' : placeholder}" rows="{rows}" style="resize: {resize}" readonly="{readonly}" disabled="{disabled}" required="{required}" minlength="{minlength}" maxlength="{maxlength}" aria-invalid="{error || validationError ? 'true' : 'false'}" aria-describedby="{error || validationError ? (id || name) + '-error' : (helperText ? (id || name) + '-help' : '')}" @input="emitField('input', event)" @change="emitField('change', event)" @focus="emitField('focus', event)" @blur="emitField('blur', event)" @invalid="handleInvalid(event)"></textarea>
|
||||
{#if variant === "floating"}<span class="wrn-next__field-floating-label">{label}</span>{/if}
|
||||
@@ -171,10 +171,10 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select) {
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
padding: 0.6rem 0.7rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid var(--wrn-color-border);
|
||||
border-radius: 0.6rem;
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
outline: 0;
|
||||
color: var(--wrn-color-text);
|
||||
background: var(--wrn-color-bg);
|
||||
@@ -188,9 +188,9 @@ size: string = "default"
|
||||
}
|
||||
.wrn-auth-form__submit > .wrn-btn {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 0.8rem 1.8rem color-mix(in srgb, var(--wrn-btn-color) 20%, transparent);
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
border-radius: var(--wrn-radius-sm, 6px);
|
||||
box-shadow: none;
|
||||
}
|
||||
.wrn-next--field :where(input, textarea, select):focus-visible {
|
||||
border-color: var(--wrn-color-primary);
|
||||
@@ -232,7 +232,7 @@ size: string = "default"
|
||||
.wrn-next__field-hint,
|
||||
.wrn-next__field-help {
|
||||
color: var(--wrn-color-muted);
|
||||
font-size: 0.82em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.wrn-next__field-control {
|
||||
@@ -246,10 +246,10 @@ size: string = "default"
|
||||
background: var(--wrn-color-surface);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="start"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="start"] > :is(input, textarea, select) {
|
||||
padding-inline-start: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-control[data-icon-position="end"] > :is(input, textarea, select) {
|
||||
.wrn-next__field-control[data-has-icon="true"][data-icon-position="end"] > :is(input, textarea, select) {
|
||||
padding-inline-end: 2.5rem;
|
||||
}
|
||||
.wrn-next__field-icon {
|
||||
@@ -357,7 +357,7 @@ size: string = "default"
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-heading {
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-heading {
|
||||
@@ -366,7 +366,7 @@ size: string = "default"
|
||||
.wrn-next--field[data-inline="true"] .wrn-next__field-help,
|
||||
.wrn-next--choice-field[data-inline="true"] .wrn-next__field-help {
|
||||
display: flex;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
}
|
||||
.wrn-next--choice-field[data-inline="true"] {
|
||||
@@ -515,7 +515,7 @@ size: string = "default"
|
||||
.wrn-next__time-trigger {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 2.65rem;
|
||||
min-height: var(--wrn-control-height, 2.5rem);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
|
||||
Reference in new issue
Block a user