refactor(ui): replace Tailwind utilities with local styles
This commit is contained in:
@@ -46,16 +46,16 @@
|
|||||||
"packages/ui/components/HeroActions.wrn": "c5720efe2ce7f6c114eb2ea4ccc3e8102a1099078ba23fd13770eddeb6aec640",
|
"packages/ui/components/HeroActions.wrn": "c5720efe2ce7f6c114eb2ea4ccc3e8102a1099078ba23fd13770eddeb6aec640",
|
||||||
"packages/ui/components/Image.wrn": "8113441bf90ab0d1d8618d477125ad339021f39e853db89d656c72c492e7a20b",
|
"packages/ui/components/Image.wrn": "8113441bf90ab0d1d8618d477125ad339021f39e853db89d656c72c492e7a20b",
|
||||||
"packages/ui/components/InputGroup.wrn": "7347865ff9b90dde690cf0753adc753a91d2ae599e92405f47e5b35806f58e06",
|
"packages/ui/components/InputGroup.wrn": "7347865ff9b90dde690cf0753adc753a91d2ae599e92405f47e5b35806f58e06",
|
||||||
"packages/ui/components/InputNumber.wrn": "3850f1cbcd314367e17244c644f1115e5ecddc7dc8248aa33fee88936c2981db",
|
"packages/ui/components/InputNumber.wrn": "0ec020084f3e556d438f8264d61f836cfab4951c52d4df60e4944fb734fb38a9",
|
||||||
"packages/ui/components/Kbd.wrn": "5afaabbb15902bd8fb82cb4155cf6cbfff55600927b54d564d27e2dd8b752386",
|
"packages/ui/components/Kbd.wrn": "5afaabbb15902bd8fb82cb4155cf6cbfff55600927b54d564d27e2dd8b752386",
|
||||||
"packages/ui/components/LayoutSplitter.wrn": "6bd6812e364420ed5d3439862116c58d0b011b298679005795bdccdbb7455066",
|
"packages/ui/components/LayoutSplitter.wrn": "6bd6812e364420ed5d3439862116c58d0b011b298679005795bdccdbb7455066",
|
||||||
"packages/ui/components/LegendIndicator.wrn": "6a7607b27a17196f899132eb952203a1073e4077365a94935f485e700cbac665",
|
"packages/ui/components/LegendIndicator.wrn": "6a7607b27a17196f899132eb952203a1073e4077365a94935f485e700cbac665",
|
||||||
"packages/ui/components/Link.wrn": "b986abcc66bc0b1c6296f3ff4e560812e35d89cc680d5251d7a3883e68c1d053",
|
"packages/ui/components/Link.wrn": "b986abcc66bc0b1c6296f3ff4e560812e35d89cc680d5251d7a3883e68c1d053",
|
||||||
"packages/ui/components/List.wrn": "11e07bbf25956c9b0116ac100c2deda0455d5e1679bfc3395450ea3a8bf23f22",
|
"packages/ui/components/List.wrn": "9bfa9613f388e5b126fc27d505e8165d7aa4a058e72132b755585464e116490e",
|
||||||
"packages/ui/components/ListGroup.wrn": "37e2ec61ceab20ed020a834da03208c493702b41abcf586816e29f2e50d8ee11",
|
"packages/ui/components/ListGroup.wrn": "37e2ec61ceab20ed020a834da03208c493702b41abcf586816e29f2e50d8ee11",
|
||||||
"packages/ui/components/Map.wrn": "2e2335a8ef3da51519478ccbc380adeb37c97ae84336c4e94d4d0ceb857f391e",
|
"packages/ui/components/Map.wrn": "9023a7a188480b24222a3910d26f6926918470369a1ab610f841c31a6120b9aa",
|
||||||
"packages/ui/components/MarketingSectionHeader.wrn": "7d6ffcc01a9331474475ea57ca58598be757abd9428b66bdfaf6f3603c5b145b",
|
"packages/ui/components/MarketingSectionHeader.wrn": "7d6ffcc01a9331474475ea57ca58598be757abd9428b66bdfaf6f3603c5b145b",
|
||||||
"packages/ui/components/Marquee.wrn": "59c6b30bfa4d3a2084a7454c856dcd2f24d20d67c559cb2434f466f418c6cd87",
|
"packages/ui/components/Marquee.wrn": "2a88c8bd8378469add26b0d937adccac4aa9f2c2005393010298e8e4fa89693e",
|
||||||
"packages/ui/components/MegaMenu.wrn": "8a9a9b348ca1c5e182914ff55d981a91f47a49c52ef5e5efd8e4cb6e56361a43",
|
"packages/ui/components/MegaMenu.wrn": "8a9a9b348ca1c5e182914ff55d981a91f47a49c52ef5e5efd8e4cb6e56361a43",
|
||||||
"packages/ui/components/MetricCard.wrn": "6451182739298691908f68258c0250cce2a78b0dc27c97115579ece30d7d9f92",
|
"packages/ui/components/MetricCard.wrn": "6451182739298691908f68258c0250cce2a78b0dc27c97115579ece30d7d9f92",
|
||||||
"packages/ui/components/MetricGrid.wrn": "6018a98c10628ed240ed236ed916c0ff60994d192c3aadafd10bc876be0f9364",
|
"packages/ui/components/MetricGrid.wrn": "6018a98c10628ed240ed236ed916c0ff60994d192c3aadafd10bc876be0f9364",
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"packages/ui/components/RangeSlider.wrn": "90ef35ceb94899dfd6e07ef3f3a88f2fb49c8dfe4596def67fe39fd9911d73c7",
|
"packages/ui/components/RangeSlider.wrn": "90ef35ceb94899dfd6e07ef3f3a88f2fb49c8dfe4596def67fe39fd9911d73c7",
|
||||||
"packages/ui/components/Rating.wrn": "a2d74dc748fc7d98892684c760518b87fa65411b1102e3611252b87245b3ffcb",
|
"packages/ui/components/Rating.wrn": "a2d74dc748fc7d98892684c760518b87fa65411b1102e3611252b87245b3ffcb",
|
||||||
"packages/ui/components/Scrollspy.wrn": "76d1c17580c8d460f1222ce97585bdcac9779141f2f30d5460c84ff9f75413d8",
|
"packages/ui/components/Scrollspy.wrn": "76d1c17580c8d460f1222ce97585bdcac9779141f2f30d5460c84ff9f75413d8",
|
||||||
"packages/ui/components/SearchBox.wrn": "ab6a78b88aef494b85a87470d4392303d9d1937a5327f1c8aa8d910f1b1829c7",
|
"packages/ui/components/SearchBox.wrn": "717f7647fabd762f8ed60a7c3306eac3ddb83c0da292a53c76d91886c2b8f94f",
|
||||||
"packages/ui/components/Section.wrn": "33eb8a82a2102229c2b1f64cec497e9e8e70b67adab8dbe396be860fccbb699c",
|
"packages/ui/components/Section.wrn": "33eb8a82a2102229c2b1f64cec497e9e8e70b67adab8dbe396be860fccbb699c",
|
||||||
"packages/ui/components/SectionHeader.wrn": "8eecf2ea7a93139512260e3d46ca2a1afeb341b8bd46b7c30baa6e2c75e25d10",
|
"packages/ui/components/SectionHeader.wrn": "8eecf2ea7a93139512260e3d46ca2a1afeb341b8bd46b7c30baa6e2c75e25d10",
|
||||||
"packages/ui/components/Sidebar.wrn": "03f1bbce75ca6d50ed940e62df39c539610e89eadd2064fe24abc7d5470f98bf",
|
"packages/ui/components/Sidebar.wrn": "03f1bbce75ca6d50ed940e62df39c539610e89eadd2064fe24abc7d5470f98bf",
|
||||||
@@ -82,9 +82,9 @@
|
|||||||
"packages/ui/components/StrongPassword.wrn": "9559756cacd10d613aea7a4ab9845a011f7f2f4613f82f83c87ab5fd2bad2ea9",
|
"packages/ui/components/StrongPassword.wrn": "9559756cacd10d613aea7a4ab9845a011f7f2f4613f82f83c87ab5fd2bad2ea9",
|
||||||
"packages/ui/components/StyledIcon.wrn": "4a4504e357dee9dd0418edbe85fc90b824ccdb3752123a2125da95b77bf0b336",
|
"packages/ui/components/StyledIcon.wrn": "4a4504e357dee9dd0418edbe85fc90b824ccdb3752123a2125da95b77bf0b336",
|
||||||
"packages/ui/components/Tabs.wrn": "e38336d28876caa4e97da32a569749e3803b030284a85ce9f35fa788e51cc5b0",
|
"packages/ui/components/Tabs.wrn": "e38336d28876caa4e97da32a569749e3803b030284a85ce9f35fa788e51cc5b0",
|
||||||
"packages/ui/components/TextLink.wrn": "30782039293eb36d63b7b3a4f32a71a47177a3a68c7e90184be7cf7b4385eb19",
|
"packages/ui/components/TextLink.wrn": "6e18906337cd3d30c2a0122593d249bde8f7cedc697b90ae388e2bd0e8eff3e1",
|
||||||
"packages/ui/components/TimePicker.wrn": "b3f24767448cb04ddd56e06540b52e5cc32ea21ed4acd2a5eb4f7e46f8617aba",
|
"packages/ui/components/TimePicker.wrn": "b3f24767448cb04ddd56e06540b52e5cc32ea21ed4acd2a5eb4f7e46f8617aba",
|
||||||
"packages/ui/components/Timeline.wrn": "eaa6764b9e62c28cb6919ac1e86d3ebe9abc3cd8036091cdb703540dbfc33873",
|
"packages/ui/components/Timeline.wrn": "686a37ebc62732842846d004491336970db94945bca942f226097d863e159d1c",
|
||||||
"packages/ui/components/Toaster.wrn": "288b2b370f65bf823e8d2a6f8c8cf66972332b8174303d33ebe8546d5e1d52c4",
|
"packages/ui/components/Toaster.wrn": "288b2b370f65bf823e8d2a6f8c8cf66972332b8174303d33ebe8546d5e1d52c4",
|
||||||
"packages/ui/components/ToggleCount.wrn": "ee706b191fcfc01dd7bde0ddba1940af400ed2d01b639016134699963b1000ab",
|
"packages/ui/components/ToggleCount.wrn": "ee706b191fcfc01dd7bde0ddba1940af400ed2d01b639016134699963b1000ab",
|
||||||
"packages/ui/components/TogglePassword.wrn": "c644436c3435b8a9b39c6b7a9f75671b76ca74f273952ce5c032ca169b0470e5",
|
"packages/ui/components/TogglePassword.wrn": "c644436c3435b8a9b39c6b7a9f75671b76ca74f273952ce5c032ca169b0470e5",
|
||||||
|
|||||||
@@ -2098,6 +2098,23 @@ const MIGRATIONS: Migration[] = [
|
|||||||
// start painting where they previously rendered as nothing.
|
// start painting where they previously rendered as nothing.
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
version: "0.8.7",
|
||||||
|
id: "0.8.7-ui-component-depth",
|
||||||
|
description:
|
||||||
|
"Removes superseded UI scaffolds and moves the remaining utility-styled components to self-contained wire-* BEM styles.",
|
||||||
|
apply() {
|
||||||
|
// AdvancedDatePicker -> DatePicker; AdvancedRangeSlider -> RangeSlider;
|
||||||
|
// FileUpload -> FileInput + FileUploadProgress (or @wrnexus/uploader);
|
||||||
|
// Toast and ToastNotifications -> Toaster.
|
||||||
|
//
|
||||||
|
// List, InputNumber, Marquee, TextLink, Map, SearchBox and Timeline no
|
||||||
|
// longer render Tailwind utility class names. Application CSS selecting
|
||||||
|
// those internal utilities must move to the component's wire-* BEM
|
||||||
|
// classes or its data-size/data-variant attributes. List now emits
|
||||||
|
// select for non-link items as well as navigation items.
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Release tooling uses this to require an explicit migration entry per version. */
|
/** Release tooling uses this to require an explicit migration entry per version. */
|
||||||
|
|||||||
@@ -118,16 +118,12 @@ are `.wrn` files rendered server-side.
|
|||||||
The framework serves this stylesheet once at `/__wrnexus/ui.css`, so pages get all
|
The framework serves this stylesheet once at `/__wrnexus/ui.css`, so pages get all
|
||||||
component styles from a single request.
|
component styles from a single request.
|
||||||
|
|
||||||
### Tailwind and motion
|
### Component styles and motion
|
||||||
|
|
||||||
Components use static Tailwind utility classes alongside the shared `.wire-*`
|
Components own their BEM styles in local `style {}` blocks and do not require a
|
||||||
layer. If the package is consumed by a separate Tailwind build, include its
|
Tailwind scan. `ui.css` supplies only global tokens, resets, and shared
|
||||||
component sources so every utility is generated:
|
primitives. Applications can still use Tailwind independently in their own
|
||||||
|
source files.
|
||||||
```css
|
|
||||||
@import "tailwindcss";
|
|
||||||
@source "../node_modules/@wrnexus/ui/components/*.wrn";
|
|
||||||
```
|
|
||||||
|
|
||||||
The shared stylesheet gives all component boundaries consistent, GPU-friendly
|
The shared stylesheet gives all component boundaries consistent, GPU-friendly
|
||||||
entry and interaction motion. Override `--wire-motion-fast`,
|
entry and interaction motion. Override `--wire-motion-fast`,
|
||||||
|
|||||||
@@ -418,19 +418,20 @@ component InputNumber {
|
|||||||
data-value='{currentValue}'
|
data-value='{currentValue}'
|
||||||
data-invalid='{isInvalid() ? "true" : "false"}'
|
data-invalid='{isInvalid() ? "true" : "false"}'
|
||||||
data-disabled='{disabled ? "true" : "false"}'
|
data-disabled='{disabled ? "true" : "false"}'
|
||||||
|
data-full-width='{fullWidth ? "true" : "false"}'
|
||||||
style='--input-number-accent: {componentColor()};'
|
style='--input-number-accent: {componentColor()};'
|
||||||
class='relative flex flex-col gap-1.5 text-[var(--wire-color-text)] {fullWidth ? "w-full" : variant === "compact" ? "w-fit max-w-full" : "w-full max-w-sm"} {disabled ? "opacity-60" : ""} {class}'
|
class='wire-input-number {class}'
|
||||||
>
|
>
|
||||||
{#if label !== "" && variant !== "labeled" && variant !== "seat"}
|
{#if label !== "" && variant !== "labeled" && variant !== "seat"}
|
||||||
<label
|
<label
|
||||||
for='{inputId()}'
|
for='{inputId()}'
|
||||||
class='inline-flex items-center gap-1 text-sm font-semibold leading-5 text-[var(--wire-color-text)]'
|
class='wire-input-number__label'
|
||||||
>
|
>
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
{#if required}
|
{#if required}
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='text-[var(--wire-color-danger)]'
|
class='wire-input-number__required'
|
||||||
>*</span>
|
>*</span>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
@@ -439,14 +440,14 @@ component InputNumber {
|
|||||||
{#if description !== "" && variant !== "labeled" && variant !== "seat"}
|
{#if description !== "" && variant !== "labeled" && variant !== "seat"}
|
||||||
<p
|
<p
|
||||||
id='{descriptionId()}'
|
id='{descriptionId()}'
|
||||||
class='m-0 text-xs leading-5 text-[var(--wire-color-muted)]'
|
class='wire-input-number__description'
|
||||||
>
|
>
|
||||||
{description}
|
{description}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class='group flex min-w-0 overflow-hidden border bg-[var(--wire-color-surface)] text-[var(--wire-color-text)] shadow-[var(--wire-shadow-1)] transition-[border-color,box-shadow,background-color] duration-[var(--wire-motion-base)] ease-[var(--wire-ease-standard)] focus-within:border-[var(--input-number-accent)] focus-within:shadow-[0_0_0_3px_color-mix(in_srgb,var(--input-number-accent)_18%,transparent)] {variant === "compact" ? "rounded-full" : "rounded-[var(--wire-radius-sm)]"} {size === "xs" ? "min-h-8 text-xs" : size === "sm" ? "min-h-9 text-sm" : size === "lg" ? "min-h-12 text-base" : size === "xl" ? "min-h-14 text-lg" : "min-h-10 text-sm"} {isInvalid() ? "border-[var(--wire-color-danger)] focus-within:border-[var(--wire-color-danger)] focus-within:shadow-[0_0_0_3px_color-mix(in_srgb,var(--wire-color-danger)_18%,transparent)]" : "border-[var(--wire-color-border)]"} {disabled ? "cursor-not-allowed bg-[var(--wire-color-surface-2)]" : ""}'
|
class='wire-input-number__control'
|
||||||
>
|
>
|
||||||
{#if variant === "horizontal" && showButtons}
|
{#if variant === "horizontal" && showButtons}
|
||||||
<button
|
<button
|
||||||
@@ -455,30 +456,30 @@ component InputNumber {
|
|||||||
aria-controls='{inputId()}'
|
aria-controls='{inputId()}'
|
||||||
disabled='{decrementDisabled()}'
|
disabled='{decrementDisabled()}'
|
||||||
@click='decrementValue(event)'
|
@click='decrementValue(event)'
|
||||||
class='inline-flex shrink-0 items-center justify-center border-r border-[var(--wire-color-border)] bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}'
|
class='wire-input-number__button wire-input-number__button--start'
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='icon-[lucide--minus] size-4'
|
class='icon-[lucide--minus] wire-input-number__icon'
|
||||||
></span>
|
></span>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class='flex min-w-0 flex-1 {variant === "labeled" ? "flex-col items-stretch justify-center gap-0.5" : variant === "seat" ? "items-center justify-between gap-3" : "items-center"} {size === "xs" ? "px-2" : size === "sm" ? "px-2.5" : size === "lg" ? "px-4" : size === "xl" ? "px-5" : "px-3"}'
|
class='wire-input-number__content'
|
||||||
>
|
>
|
||||||
{#if variant === "labeled" || variant === "seat"}
|
{#if variant === "labeled" || variant === "seat"}
|
||||||
<div class='min-w-0 flex-1'>
|
<div class='wire-input-number__copy'>
|
||||||
{#if label !== ""}
|
{#if label !== ""}
|
||||||
<label
|
<label
|
||||||
for='{inputId()}'
|
for='{inputId()}'
|
||||||
class='block truncate font-semibold leading-4 text-[var(--wire-color-text)] {variant === "labeled" ? "text-xs font-medium text-[var(--wire-color-muted)]" : "text-sm"}'
|
class='wire-input-number__inner-label'
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
{#if required}
|
{#if required}
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='ml-0.5 text-[var(--wire-color-danger)]'
|
class='wire-input-number__required'
|
||||||
>*</span>
|
>*</span>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
@@ -487,7 +488,7 @@ component InputNumber {
|
|||||||
{#if description !== ""}
|
{#if description !== ""}
|
||||||
<span
|
<span
|
||||||
id='{descriptionId()}'
|
id='{descriptionId()}'
|
||||||
class='block truncate text-xs leading-4 text-[var(--wire-color-muted)]'
|
class='wire-input-number__inner-description'
|
||||||
>
|
>
|
||||||
{description}
|
{description}
|
||||||
</span>
|
</span>
|
||||||
@@ -496,12 +497,12 @@ component InputNumber {
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class='flex min-w-0 items-center {variant === "seat" ? "w-auto shrink-0" : "w-full"}'
|
class='wire-input-number__field'
|
||||||
>
|
>
|
||||||
{#if prefix !== ""}
|
{#if prefix !== ""}
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='shrink-0 pr-1.5 text-[var(--wire-color-muted)]'
|
class='wire-input-number__prefix'
|
||||||
>
|
>
|
||||||
{prefix}
|
{prefix}
|
||||||
</span>
|
</span>
|
||||||
@@ -531,13 +532,13 @@ component InputNumber {
|
|||||||
@change='handleChange(event)'
|
@change='handleChange(event)'
|
||||||
@keydown='handleKeydown(event)'
|
@keydown='handleKeydown(event)'
|
||||||
@wheel='handleWheel(event)'
|
@wheel='handleWheel(event)'
|
||||||
class='min-w-0 flex-1 appearance-none border-0 bg-transparent p-0 font-medium leading-none text-[var(--wire-color-text)] outline-none placeholder:text-[var(--wire-color-muted)] read-only:cursor-default disabled:cursor-not-allowed [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none {variant === "horizontal" || variant === "compact" || variant === "seat" ? "text-center" : "text-left"} {variant === "seat" ? "w-10 flex-none" : "w-full"}'
|
class='wire-input-number__input'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if suffix !== ""}
|
{#if suffix !== ""}
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='shrink-0 pl-1.5 text-[var(--wire-color-muted)]'
|
class='wire-input-number__suffix'
|
||||||
>
|
>
|
||||||
{suffix}
|
{suffix}
|
||||||
</span>
|
</span>
|
||||||
@@ -552,11 +553,11 @@ component InputNumber {
|
|||||||
aria-controls='{inputId()}'
|
aria-controls='{inputId()}'
|
||||||
disabled='{incrementDisabled()}'
|
disabled='{incrementDisabled()}'
|
||||||
@click='incrementValue(event)'
|
@click='incrementValue(event)'
|
||||||
class='inline-flex shrink-0 items-center justify-center border-l border-[var(--wire-color-border)] bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}'
|
class='wire-input-number__button wire-input-number__button--end'
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='icon-[lucide--plus] size-4'
|
class='icon-[lucide--plus] wire-input-number__icon'
|
||||||
></span>
|
></span>
|
||||||
</button>
|
</button>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -564,7 +565,7 @@ component InputNumber {
|
|||||||
<div
|
<div
|
||||||
role="group"
|
role="group"
|
||||||
aria-label='{controlsLabel}'
|
aria-label='{controlsLabel}'
|
||||||
class='flex shrink-0 border-l border-[var(--wire-color-border)] {variant === "vertical" ? "flex-col" : "flex-row"}'
|
class='wire-input-number__buttons'
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -572,11 +573,11 @@ component InputNumber {
|
|||||||
aria-controls='{inputId()}'
|
aria-controls='{inputId()}'
|
||||||
disabled='{decrementDisabled()}'
|
disabled='{decrementDisabled()}'
|
||||||
@click='decrementValue(event)'
|
@click='decrementValue(event)'
|
||||||
class='inline-flex items-center justify-center bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {variant === "vertical" ? "flex-1 border-b border-[var(--wire-color-border)]" : "border-r border-[var(--wire-color-border)]"} {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}'
|
class='wire-input-number__button wire-input-number__button--decrement'
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='icon-[lucide--minus] size-4'
|
class='icon-[lucide--minus] wire-input-number__icon'
|
||||||
></span>
|
></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -586,11 +587,11 @@ component InputNumber {
|
|||||||
aria-controls='{inputId()}'
|
aria-controls='{inputId()}'
|
||||||
disabled='{incrementDisabled()}'
|
disabled='{incrementDisabled()}'
|
||||||
@click='incrementValue(event)'
|
@click='incrementValue(event)'
|
||||||
class='inline-flex items-center justify-center bg-transparent text-[var(--wire-color-muted)] transition-[color,background-color] duration-[var(--wire-motion-fast)] hover:bg-[var(--wire-color-surface-2)] hover:text-[var(--input-number-accent)] focus-visible:z-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--input-number-accent)] disabled:cursor-not-allowed disabled:opacity-40 {variant === "vertical" ? "flex-1" : ""} {size === "xs" ? "w-8" : size === "sm" ? "w-9" : size === "lg" ? "w-12" : size === "xl" ? "w-14" : "w-10"}'
|
class='wire-input-number__button wire-input-number__button--increment'
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='icon-[lucide--plus] size-4'
|
class='icon-[lucide--plus] wire-input-number__icon'
|
||||||
></span>
|
></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -603,11 +604,11 @@ component InputNumber {
|
|||||||
id='{messageId()}'
|
id='{messageId()}'
|
||||||
role="alert"
|
role="alert"
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
class='m-0 flex items-center gap-1.5 text-xs leading-5 text-[var(--wire-color-danger)]'
|
class='wire-input-number__message wire-input-number__message--error'
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class='icon-[lucide--circle-alert] size-3.5 shrink-0'
|
class='icon-[lucide--circle-alert] wire-input-number__error-icon'
|
||||||
></span>
|
></span>
|
||||||
<span>{validationMessage()}</span>
|
<span>{validationMessage()}</span>
|
||||||
</p>
|
</p>
|
||||||
@@ -616,11 +617,66 @@ component InputNumber {
|
|||||||
{#if (!showValidationMessage || !isInvalid() || validationMessage() === "") && helpText !== ""}
|
{#if (!showValidationMessage || !isInvalid() || validationMessage() === "") && helpText !== ""}
|
||||||
<p
|
<p
|
||||||
id='{messageId()}'
|
id='{messageId()}'
|
||||||
class='m-0 text-xs leading-5 text-[var(--wire-color-muted)]'
|
class='wire-input-number__message'
|
||||||
>
|
>
|
||||||
{helpText}
|
{helpText}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
style {
|
||||||
|
.wire-input-number { position: relative; display: flex; width: 100%; max-width: 24rem; flex-direction: column; gap: 0.375rem; color: var(--wire-color-text); }
|
||||||
|
.wire-input-number[data-full-width="true"] { max-width: none; }
|
||||||
|
.wire-input-number[data-variant="compact"] { width: fit-content; max-width: 100%; }
|
||||||
|
.wire-input-number[data-disabled="true"] { opacity: 0.6; }
|
||||||
|
.wire-input-number__label { display: inline-flex; align-items: center; gap: 0.25rem; color: var(--wire-color-text); font-size: 0.875rem; font-weight: 600; line-height: 1.25rem; }
|
||||||
|
.wire-input-number__required { margin-left: 0.125rem; color: var(--wire-color-danger); }
|
||||||
|
.wire-input-number__description, .wire-input-number__message { margin: 0; color: var(--wire-color-muted); font-size: 0.75rem; line-height: 1.25rem; }
|
||||||
|
.wire-input-number__control { display: flex; min-width: 0; min-height: 2.5rem; overflow: hidden; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius-sm); color: var(--wire-color-text); background: var(--wire-color-surface); box-shadow: var(--wire-shadow-1); transition: border-color var(--wire-motion-base), box-shadow var(--wire-motion-base), background var(--wire-motion-base); }
|
||||||
|
.wire-input-number__control:focus-within { border-color: var(--input-number-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--input-number-accent) 18%, transparent); }
|
||||||
|
.wire-input-number[data-invalid="true"] .wire-input-number__control { border-color: var(--wire-color-danger); }
|
||||||
|
.wire-input-number[data-invalid="true"] .wire-input-number__control:focus-within { box-shadow: 0 0 0 3px color-mix(in srgb, var(--wire-color-danger) 18%, transparent); }
|
||||||
|
.wire-input-number[data-disabled="true"] .wire-input-number__control { cursor: not-allowed; background: var(--wire-color-surface-2); }
|
||||||
|
.wire-input-number[data-variant="compact"] .wire-input-number__control { border-radius: 999px; }
|
||||||
|
.wire-input-number[data-size="xs"] .wire-input-number__control { min-height: 2rem; font-size: 0.75rem; }
|
||||||
|
.wire-input-number[data-size="sm"] .wire-input-number__control { min-height: 2.25rem; font-size: 0.875rem; }
|
||||||
|
.wire-input-number[data-size="lg"] .wire-input-number__control { min-height: 3rem; font-size: 1rem; }
|
||||||
|
.wire-input-number[data-size="xl"] .wire-input-number__control { min-height: 3.5rem; font-size: 1.125rem; }
|
||||||
|
.wire-input-number__content { display: flex; min-width: 0; flex: 1; align-items: center; padding-inline: 0.75rem; }
|
||||||
|
.wire-input-number[data-size="xs"] .wire-input-number__content { padding-inline: 0.5rem; }
|
||||||
|
.wire-input-number[data-size="sm"] .wire-input-number__content { padding-inline: 0.625rem; }
|
||||||
|
.wire-input-number[data-size="lg"] .wire-input-number__content { padding-inline: 1rem; }
|
||||||
|
.wire-input-number[data-size="xl"] .wire-input-number__content { padding-inline: 1.25rem; }
|
||||||
|
.wire-input-number[data-variant="labeled"] .wire-input-number__content { flex-direction: column; align-items: stretch; justify-content: center; gap: 0.125rem; }
|
||||||
|
.wire-input-number[data-variant="seat"] .wire-input-number__content { justify-content: space-between; gap: 0.75rem; }
|
||||||
|
.wire-input-number__copy { min-width: 0; flex: 1; }
|
||||||
|
.wire-input-number__inner-label, .wire-input-number__inner-description { display: block; overflow: hidden; color: var(--wire-color-text); font-size: 0.875rem; font-weight: 600; line-height: 1rem; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.wire-input-number__inner-description { color: var(--wire-color-muted); font-size: 0.75rem; font-weight: 400; }
|
||||||
|
.wire-input-number[data-variant="labeled"] .wire-input-number__inner-label { color: var(--wire-color-muted); font-size: 0.75rem; font-weight: 500; }
|
||||||
|
.wire-input-number__field { display: flex; width: 100%; min-width: 0; align-items: center; }
|
||||||
|
.wire-input-number[data-variant="seat"] .wire-input-number__field { width: auto; flex: none; }
|
||||||
|
.wire-input-number__prefix, .wire-input-number__suffix { flex: none; color: var(--wire-color-muted); }
|
||||||
|
.wire-input-number__prefix { padding-right: 0.375rem; } .wire-input-number__suffix { padding-left: 0.375rem; }
|
||||||
|
.wire-input-number__input { width: 100%; min-width: 0; flex: 1; padding: 0; border: 0; outline: none; color: var(--wire-color-text); background: transparent; font: inherit; font-weight: 500; line-height: 1; appearance: textfield; }
|
||||||
|
.wire-input-number__input::-webkit-inner-spin-button, .wire-input-number__input::-webkit-outer-spin-button { appearance: none; }
|
||||||
|
.wire-input-number__input::placeholder { color: var(--wire-color-muted); }
|
||||||
|
.wire-input-number__input:read-only { cursor: default; }
|
||||||
|
.wire-input-number__input:disabled { cursor: not-allowed; }
|
||||||
|
.wire-input-number:is([data-variant="horizontal"], [data-variant="compact"], [data-variant="seat"]) .wire-input-number__input { text-align: center; }
|
||||||
|
.wire-input-number[data-variant="seat"] .wire-input-number__input { width: 2.5rem; flex: none; }
|
||||||
|
.wire-input-number__buttons { display: flex; flex: none; border-left: 1px solid var(--wire-color-border); }
|
||||||
|
.wire-input-number[data-variant="vertical"] .wire-input-number__buttons { flex-direction: column; }
|
||||||
|
.wire-input-number__button { display: inline-flex; width: 2.5rem; flex: none; align-items: center; justify-content: center; padding: 0; border: 0; color: var(--wire-color-muted); background: transparent; transition: color var(--wire-motion-fast), background var(--wire-motion-fast); }
|
||||||
|
.wire-input-number[data-size="xs"] .wire-input-number__button { width: 2rem; } .wire-input-number[data-size="sm"] .wire-input-number__button { width: 2.25rem; } .wire-input-number[data-size="lg"] .wire-input-number__button { width: 3rem; } .wire-input-number[data-size="xl"] .wire-input-number__button { width: 3.5rem; }
|
||||||
|
.wire-input-number__button--start { border-right: 1px solid var(--wire-color-border); } .wire-input-number__button--end { border-left: 1px solid var(--wire-color-border); }
|
||||||
|
.wire-input-number__button--decrement { border-right: 1px solid var(--wire-color-border); }
|
||||||
|
.wire-input-number[data-variant="vertical"] .wire-input-number__button--decrement { border-right: 0; border-bottom: 1px solid var(--wire-color-border); }
|
||||||
|
.wire-input-number__button:hover { color: var(--input-number-accent); background: var(--wire-color-surface-2); }
|
||||||
|
.wire-input-number__button:focus-visible { z-index: 1; outline: 2px solid var(--input-number-accent); outline-offset: -2px; }
|
||||||
|
.wire-input-number__button:disabled { cursor: not-allowed; opacity: 0.4; }
|
||||||
|
.wire-input-number__icon { width: 1rem; height: 1rem; }
|
||||||
|
.wire-input-number__message--error { display: flex; align-items: center; gap: 0.375rem; color: var(--wire-color-danger); }
|
||||||
|
.wire-input-number__error-icon { width: 0.875rem; height: 0.875rem; flex: none; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,89 +17,76 @@ component List {
|
|||||||
<section
|
<section
|
||||||
data-ui-component="List"
|
data-ui-component="List"
|
||||||
aria-label='{title}'
|
aria-label='{title}'
|
||||||
class='w-full {class}'
|
class='wire-list {class}'
|
||||||
>
|
>
|
||||||
{#if title || description}
|
{#if title || description}
|
||||||
<header class="mb-4">
|
<header class="wire-list__header">
|
||||||
{#if title}
|
{#if title}
|
||||||
<h3 class="text-lg font-bold text-[var(--wire-color-text)]">{title}</h3>
|
<h3 class="wire-list__title">{title}</h3>
|
||||||
{/if}
|
{/if}
|
||||||
{#if description}
|
{#if description}
|
||||||
<p class="mt-1 text-sm leading-6 text-[var(--wire-color-text-muted)]">{description}</p>
|
<p class="wire-list__description">{description}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</header>
|
</header>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<ul
|
<ul
|
||||||
class="overflow-hidden"
|
class="wire-list__items"
|
||||||
class:divide-y='variant === "default" || variant === "divided"'
|
data-variant='{variant}'
|
||||||
class:divide-[var(--wire-color-border)]='variant === "default" || variant === "divided"'
|
|
||||||
class:rounded-2xl='variant === "card"'
|
|
||||||
class:border='variant === "card"'
|
|
||||||
class:border-[var(--wire-color-border)]='variant === "card"'
|
|
||||||
class:bg-[var(--wire-color-surface-raised)]='variant === "card"'
|
|
||||||
class:space-y-3='variant === "separated"'
|
|
||||||
>
|
>
|
||||||
{#each items as item, index}
|
{#each items as item, index}
|
||||||
<li
|
<li
|
||||||
class="group min-w-0"
|
class="wire-list__item"
|
||||||
class:rounded-xl='variant === "separated"'
|
data-variant='{variant}'
|
||||||
class:border='variant === "separated"'
|
@click='if (!item.href) { output.select({ item: item, index: index }) }'
|
||||||
class:border-[var(--wire-color-border)]='variant === "separated"'
|
|
||||||
class:bg-[var(--wire-color-surface-raised)]='variant === "separated"'
|
|
||||||
>
|
>
|
||||||
{#if item.href}
|
{#if item.href}
|
||||||
<a
|
<a
|
||||||
href='{item.href}'
|
href='{item.href}'
|
||||||
class="flex min-w-0 items-start gap-3 px-4 py-3 outline-none transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]"
|
class="wire-list__row"
|
||||||
class:px-3='size === "sm"'
|
data-size='{size}'
|
||||||
class:py-2.5='size === "sm"'
|
|
||||||
class:px-5='size === "lg"'
|
|
||||||
class:py-4='size === "lg"'
|
|
||||||
@click='output.select({ item: item, index: index })'
|
@click='output.select({ item: item, index: index })'
|
||||||
>
|
>
|
||||||
{#if item.icon}
|
{#if item.icon}
|
||||||
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]">
|
<span class="wire-list__leading-icon"><span class='{item.icon}' aria-hidden="true"></span>
|
||||||
<span class='{item.icon + " size-5"}' aria-hidden="true"></span>
|
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
{#if item.imageSrc}
|
{#if item.imageSrc}
|
||||||
<img src='{item.imageSrc}' alt='{item.imageAlt || ""}' class="size-12 shrink-0 rounded-xl object-cover" loading="lazy" />
|
<img src='{item.imageSrc}' alt='{item.imageAlt || ""}' class="wire-list__image" loading="lazy" />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="min-w-0 flex-1">
|
<div class="wire-list__body">
|
||||||
<div class="flex items-start justify-between gap-3">
|
<div class="wire-list__heading">
|
||||||
<p class="truncate font-semibold text-[var(--wire-color-text)]">{item.title || item.label}</p>
|
<p class="wire-list__item-title">{item.title || item.label}</p>
|
||||||
{#if item.meta}
|
{#if item.meta}
|
||||||
<span class="shrink-0 text-xs text-[var(--wire-color-text-muted)]">{item.meta}</span>
|
<span class="wire-list__meta">{item.meta}</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if item.description}
|
{#if item.description}
|
||||||
<p class="mt-1 line-clamp-2 text-sm leading-5 text-[var(--wire-color-text-muted)]">{item.description}</p>
|
<p class="wire-list__item-description">{item.description}</p>
|
||||||
{/if}
|
{/if}
|
||||||
{#if item.badge}
|
{#if item.badge}
|
||||||
<span class="mt-2 inline-flex rounded-full bg-[var(--wire-color-primary-soft)] px-2.5 py-1 text-xs font-semibold text-[var(--wire-color-primary)]">{item.badge}</span>
|
<span class="wire-list__badge">{item.badge}</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<span class="icon-[lucide--chevron-right] mt-1 size-4 shrink-0 text-[var(--wire-color-text-muted)] transition group-hover:translate-x-0.5 group-hover:text-[var(--wire-color-primary)]" aria-hidden="true"></span>
|
<span class="icon-[lucide--chevron-right] wire-list__chevron" aria-hidden="true"></span>
|
||||||
</a>
|
</a>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex min-w-0 items-start gap-3 px-4 py-3">
|
<div class="wire-list__row" data-size='{size}'>
|
||||||
{#if item.icon}
|
{#if item.icon}
|
||||||
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]">
|
<span class="wire-list__leading-icon"><span class='{item.icon}' aria-hidden="true"></span>
|
||||||
<span class='{item.icon + " size-5"}' aria-hidden="true"></span>
|
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="min-w-0 flex-1">
|
<div class="wire-list__body">
|
||||||
<p class="font-semibold text-[var(--wire-color-text)]">{item.title || item.label}</p>
|
<p class="wire-list__item-title">{item.title || item.label}</p>
|
||||||
{#if item.description}
|
{#if item.description}
|
||||||
<p class="mt-1 text-sm leading-5 text-[var(--wire-color-text-muted)]">{item.description}</p>
|
<p class="wire-list__item-description">{item.description}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
{:empty}
|
{:empty}
|
||||||
<li class="rounded-xl border border-dashed border-[var(--wire-color-border)] p-6 text-center text-sm text-[var(--wire-color-text-muted)]">
|
<li class="wire-list__empty">
|
||||||
No items available.
|
No items available.
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -108,4 +95,34 @@ component List {
|
|||||||
<slot></slot>
|
<slot></slot>
|
||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
style {
|
||||||
|
.wire-list { width: 100%; }
|
||||||
|
.wire-list__header { margin-bottom: 1rem; }
|
||||||
|
.wire-list__title { color: var(--wire-color-text); font-size: 1.125rem; font-weight: 700; }
|
||||||
|
.wire-list__description { margin-top: 0.25rem; color: var(--wire-color-text-muted); font-size: 0.875rem; line-height: 1.5rem; }
|
||||||
|
.wire-list__items { overflow: hidden; }
|
||||||
|
.wire-list__items:is([data-variant="default"], [data-variant="divided"]) > .wire-list__item + .wire-list__item { border-top: 1px solid var(--wire-color-border); }
|
||||||
|
.wire-list__items[data-variant="card"] { border: 1px solid var(--wire-color-border); border-radius: calc(var(--wire-radius) * 1.5); background: var(--wire-color-surface-raised); }
|
||||||
|
.wire-list__items[data-variant="separated"] { display: grid; gap: 0.75rem; }
|
||||||
|
.wire-list__item { min-width: 0; }
|
||||||
|
.wire-list__item[data-variant="separated"] { border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius); background: var(--wire-color-surface-raised); }
|
||||||
|
.wire-list__row { display: flex; min-width: 0; align-items: flex-start; gap: 0.75rem; padding: 0.75rem 1rem; outline: none; transition: background var(--wire-motion-base); }
|
||||||
|
a.wire-list__row:hover { background: var(--wire-color-surface-soft); }
|
||||||
|
.wire-list__row:focus-visible { box-shadow: inset 0 0 0 2px var(--wire-color-focus); }
|
||||||
|
.wire-list__row[data-size="sm"] { padding: 0.625rem 0.75rem; }
|
||||||
|
.wire-list__row[data-size="lg"] { padding: 1rem 1.25rem; }
|
||||||
|
.wire-list__leading-icon { display: flex; width: 2.5rem; height: 2.5rem; flex: none; align-items: center; justify-content: center; border-radius: var(--wire-radius); color: var(--wire-color-primary); background: var(--wire-color-primary-soft); }
|
||||||
|
.wire-list__leading-icon > span { width: 1.25rem; height: 1.25rem; }
|
||||||
|
.wire-list__image { width: 3rem; height: 3rem; flex: none; border-radius: var(--wire-radius); object-fit: cover; }
|
||||||
|
.wire-list__body { min-width: 0; flex: 1; }
|
||||||
|
.wire-list__heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; }
|
||||||
|
.wire-list__item-title { overflow: hidden; color: var(--wire-color-text); font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.wire-list__meta { flex: none; color: var(--wire-color-text-muted); font-size: 0.75rem; }
|
||||||
|
.wire-list__item-description { display: -webkit-box; margin-top: 0.25rem; overflow: hidden; color: var(--wire-color-text-muted); font-size: 0.875rem; line-height: 1.25rem; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
|
||||||
|
.wire-list__badge { display: inline-flex; margin-top: 0.5rem; padding: 0.25rem 0.625rem; border-radius: 999px; color: var(--wire-color-primary); background: var(--wire-color-primary-soft); font-size: 0.75rem; font-weight: 600; }
|
||||||
|
.wire-list__chevron { width: 1rem; height: 1rem; flex: none; margin-top: 0.25rem; color: var(--wire-color-text-muted); transition: color var(--wire-motion-base), transform var(--wire-motion-base); }
|
||||||
|
.wire-list__row:hover .wire-list__chevron { color: var(--wire-color-primary); transform: translateX(0.125rem); }
|
||||||
|
.wire-list__empty { padding: 1.5rem; border: 1px dashed var(--wire-color-border); border-radius: var(--wire-radius); color: var(--wire-color-text-muted); font-size: 0.875rem; text-align: center; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,37 +21,34 @@ component Map {
|
|||||||
<section
|
<section
|
||||||
data-ui-component="Map"
|
data-ui-component="Map"
|
||||||
aria-label='{title}'
|
aria-label='{title}'
|
||||||
class='overflow-hidden rounded-2xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] shadow-sm {class}'
|
class='wire-map {class}'
|
||||||
>
|
>
|
||||||
{#if title || description}
|
{#if title || description}
|
||||||
<header class="flex items-start justify-between gap-4 border-b border-[var(--wire-color-border)] p-5">
|
<header class="wire-map__header">
|
||||||
<div>
|
<div>
|
||||||
{#if title}
|
{#if title}
|
||||||
<h3 class="text-lg font-bold text-[var(--wire-color-text)]">{title}</h3>
|
<h3 class="wire-map__title">{title}</h3>
|
||||||
{/if}
|
{/if}
|
||||||
{#if description}
|
{#if description}
|
||||||
<p class="mt-1 text-sm leading-6 text-[var(--wire-color-text-muted)]">{description}</p>
|
<p class="wire-map__description">{description}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<span class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[var(--wire-color-primary-soft)] text-[var(--wire-color-primary)]">
|
<span class="wire-map__header-icon"><span class="icon-[lucide--map]" aria-hidden="true"></span>
|
||||||
<span class="icon-[lucide--map] size-5" aria-hidden="true"></span>
|
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="relative isolate overflow-hidden bg-[var(--wire-color-surface-soft)]"
|
class="wire-map__viewport"
|
||||||
class:h-64='size === "sm"'
|
data-size='{size}'
|
||||||
class:h-80='size === "default" || size === "md"'
|
|
||||||
class:h-[28rem]='size === "lg"'
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="pointer-events-none absolute inset-0 opacity-50"
|
class="wire-map__grid"
|
||||||
style="background-image: linear-gradient(var(--wire-color-border) 1px, transparent 1px), linear-gradient(90deg, var(--wire-color-border) 1px, transparent 1px); background-size: 32px 32px;"
|
style="background-image: linear-gradient(var(--wire-color-border) 1px, transparent 1px), linear-gradient(90deg, var(--wire-color-border) 1px, transparent 1px); background-size: 32px 32px;"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<div class="absolute inset-0 flex items-center justify-center p-6">
|
<div class="wire-map__content">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -60,7 +57,7 @@ component Map {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label='{item.label || item.title || "Map marker"}'
|
aria-label='{item.label || item.title || "Map marker"}'
|
||||||
class="absolute inline-flex size-10 items-center justify-center rounded-full border-4 border-[var(--wire-color-surface-raised)] bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] shadow-lg transition hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
class="wire-map__marker"
|
||||||
style='left: {item.x || (20 + index * 12)}%; top: {item.y || (30 + (index % 3) * 18)}%;'
|
style='left: {item.x || (20 + index * 12)}%; top: {item.y || (30 + (index % 3) * 18)}%;'
|
||||||
@click='output.markerClick(item); output.select(item)'
|
@click='output.markerClick(item); output.select(item)'
|
||||||
>
|
>
|
||||||
@@ -69,25 +66,46 @@ component Map {
|
|||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="absolute bottom-4 right-4 flex flex-col gap-2">
|
<div class="wire-map__controls">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Zoom in"
|
aria-label="Zoom in"
|
||||||
class="inline-flex size-10 items-center justify-center rounded-xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] text-[var(--wire-color-text)] shadow-sm transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
class="wire-map__control"
|
||||||
@click='output.zoom({ direction: "in" })'
|
@click='output.zoom({ direction: "in" })'
|
||||||
>
|
>
|
||||||
<span class="icon-[lucide--plus] size-4" aria-hidden="true"></span>
|
<span class="icon-[lucide--plus] wire-map__control-icon" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Zoom out"
|
aria-label="Zoom out"
|
||||||
class="inline-flex size-10 items-center justify-center rounded-xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] text-[var(--wire-color-text)] shadow-sm transition hover:bg-[var(--wire-color-surface-soft)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
class="wire-map__control"
|
||||||
@click='output.zoom({ direction: "out" })'
|
@click='output.zoom({ direction: "out" })'
|
||||||
>
|
>
|
||||||
<span class="icon-[lucide--minus] size-4" aria-hidden="true"></span>
|
<span class="icon-[lucide--minus] wire-map__control-icon" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
style {
|
||||||
|
.wire-map { overflow: hidden; border: 1px solid var(--wire-color-border); border-radius: calc(var(--wire-radius) * 1.5); background: var(--wire-color-surface-raised); box-shadow: var(--wire-shadow-1); }
|
||||||
|
.wire-map__header { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: 1.25rem; border-bottom: 1px solid var(--wire-color-border); }
|
||||||
|
.wire-map__title { color: var(--wire-color-text); font-size: 1.125rem; font-weight: 700; }
|
||||||
|
.wire-map__description { margin-top: 0.25rem; color: var(--wire-color-text-muted); font-size: 0.875rem; line-height: 1.5rem; }
|
||||||
|
.wire-map__header-icon { display: flex; width: 2.5rem; height: 2.5rem; flex: none; align-items: center; justify-content: center; border-radius: var(--wire-radius); color: var(--wire-color-primary); background: var(--wire-color-primary-soft); }
|
||||||
|
.wire-map__header-icon > span { width: 1.25rem; height: 1.25rem; }
|
||||||
|
.wire-map__viewport { position: relative; isolation: isolate; height: 20rem; overflow: hidden; background: var(--wire-color-surface-soft); }
|
||||||
|
.wire-map__viewport[data-size="sm"] { height: 16rem; }
|
||||||
|
.wire-map__viewport[data-size="lg"] { height: 28rem; }
|
||||||
|
.wire-map__grid { position: absolute; inset: 0; opacity: 0.5; pointer-events: none; }
|
||||||
|
.wire-map__content { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 1.5rem; }
|
||||||
|
.wire-map__marker { position: absolute; display: inline-flex; width: 2.5rem; height: 2.5rem; align-items: center; justify-content: center; padding: 0; border: 4px solid var(--wire-color-surface-raised); border-radius: 50%; color: var(--wire-color-on-primary); background: var(--wire-color-primary); box-shadow: var(--wire-shadow-3); transition: transform var(--wire-motion-base) var(--wire-ease-standard); }
|
||||||
|
.wire-map__marker:hover { transform: scale(1.1); }
|
||||||
|
.wire-map__controls { position: absolute; right: 1rem; bottom: 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
|
||||||
|
.wire-map__control { display: inline-flex; width: 2.5rem; height: 2.5rem; align-items: center; justify-content: center; padding: 0; border: 1px solid var(--wire-color-border); border-radius: var(--wire-radius); color: var(--wire-color-text); background: var(--wire-color-surface-raised); box-shadow: var(--wire-shadow-1); transition: background var(--wire-motion-base); }
|
||||||
|
.wire-map__control:hover { background: var(--wire-color-surface-soft); }
|
||||||
|
.wire-map__marker:focus-visible, .wire-map__control:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: 2px; }
|
||||||
|
.wire-map__control-icon { width: 1rem; height: 1rem; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,46 +21,44 @@ component Marquee {
|
|||||||
<section
|
<section
|
||||||
data-ui-component="Marquee"
|
data-ui-component="Marquee"
|
||||||
aria-label='{title}'
|
aria-label='{title}'
|
||||||
class='overflow-hidden border-y border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] {class}'
|
class='wire-marquee {class}'
|
||||||
>
|
>
|
||||||
<div class="flex items-stretch">
|
<div class="wire-marquee__layout">
|
||||||
{#if title}
|
{#if title}
|
||||||
<div class="relative z-10 flex shrink-0 items-center gap-2 border-r border-[var(--wire-color-border)] bg-[var(--wire-color-primary)] px-4 py-3 text-[var(--wire-color-on-primary)] sm:px-5">
|
<div class="wire-marquee__title">
|
||||||
<span class="icon-[lucide--megaphone] size-4" aria-hidden="true"></span>
|
<span class="icon-[lucide--megaphone] wire-marquee__icon" aria-hidden="true"></span>
|
||||||
<span class="text-sm font-bold">{title}</span>
|
<span>{title}</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="group relative min-w-0 flex-1 overflow-hidden"
|
class="wire-marquee__window"
|
||||||
@mouseenter='paused = true; output.pause({})'
|
@mouseenter='paused = true; output.pause({})'
|
||||||
@mouseleave='paused = false; output.resume({})'
|
@mouseleave='paused = false; output.resume({})'
|
||||||
@focusin='paused = true'
|
@focusin='paused = true'
|
||||||
@focusout='paused = false'
|
@focusout='paused = false'
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="wire-marquee-track flex w-max min-w-full items-center"
|
class="wire-marquee__track"
|
||||||
class:wire-marquee-paused='paused'
|
class:wire-marquee-paused='paused'
|
||||||
>
|
>
|
||||||
{#each items as item}
|
{#each items as item}
|
||||||
<a
|
<a
|
||||||
href='{item.href || "#"}'
|
href='{item.href || "#"}'
|
||||||
class="flex shrink-0 items-center gap-3 px-5 py-3 text-sm font-medium text-[var(--wire-color-text)] transition hover:bg-[var(--wire-color-primary-soft)] hover:text-[var(--wire-color-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]"
|
class="wire-marquee__item"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="size-2 shrink-0 rounded-full bg-[var(--wire-color-primary)]"
|
class="wire-marquee__dot"
|
||||||
class:bg-[var(--wire-color-danger)]='item.color === "danger"'
|
data-color='{item.color || "primary"}'
|
||||||
class:bg-[var(--wire-color-warning)]='item.color === "warning"'
|
|
||||||
class:bg-[var(--wire-color-success)]='item.color === "success"'
|
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></span>
|
></span>
|
||||||
<span>{item.label || item.title}</span>
|
<span>{item.label || item.title}</span>
|
||||||
{#if item.meta}
|
{#if item.meta}
|
||||||
<span class="text-xs text-[var(--wire-color-text-muted)]">{item.meta}</span>
|
<span class="wire-marquee__meta">{item.meta}</span>
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
{:empty}
|
{:empty}
|
||||||
<p class="px-5 py-3 text-sm text-[var(--wire-color-text-muted)]">{description || "No announcements available."}</p>
|
<p class="wire-marquee__empty">{description || "No announcements available."}</p>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if items.length > 0}
|
{#if items.length > 0}
|
||||||
@@ -69,9 +67,9 @@ component Marquee {
|
|||||||
href='{item.href || "#"}'
|
href='{item.href || "#"}'
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
class="flex shrink-0 items-center gap-3 px-5 py-3 text-sm font-medium text-[var(--wire-color-text)]"
|
class="wire-marquee__item"
|
||||||
>
|
>
|
||||||
<span class="size-2 shrink-0 rounded-full bg-[var(--wire-color-primary)]" aria-hidden="true"></span>
|
<span class="wire-marquee__dot" aria-hidden="true"></span>
|
||||||
<span>{item.label || item.title}</span>
|
<span>{item.label || item.title}</span>
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -82,11 +80,11 @@ component Marquee {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label='{paused ? "Resume announcements" : "Pause announcements"}'
|
aria-label='{paused ? "Resume announcements" : "Pause announcements"}'
|
||||||
class="flex shrink-0 items-center justify-center border-l border-[var(--wire-color-border)] px-4 text-[var(--wire-color-text-muted)] transition hover:bg-[var(--wire-color-surface-soft)] hover:text-[var(--wire-color-text)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--wire-color-focus)]"
|
class="wire-marquee__toggle"
|
||||||
@click='paused = !paused; paused ? output.pause({}) : output.resume({})'
|
@click='paused = !paused; paused ? output.pause({}) : output.resume({})'
|
||||||
>
|
>
|
||||||
<span class="icon-[lucide--pause] size-4" data-show='!paused' aria-hidden="true"></span>
|
<span class="icon-[lucide--pause] wire-marquee__icon" data-show='!paused' aria-hidden="true"></span>
|
||||||
<span class="icon-[lucide--play] size-4" data-show='paused' aria-hidden="true"></span>
|
<span class="icon-[lucide--play] wire-marquee__icon" data-show='paused' aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -95,9 +93,28 @@ component Marquee {
|
|||||||
}
|
}
|
||||||
|
|
||||||
style {
|
style {
|
||||||
.wire-marquee-track {
|
.wire-marquee { overflow: hidden; border-block: 1px solid var(--wire-color-border); background: var(--wire-color-surface-raised); }
|
||||||
|
.wire-marquee__layout { display: flex; align-items: stretch; }
|
||||||
|
.wire-marquee__title { position: relative; z-index: 1; display: flex; flex: none; align-items: center; gap: 0.5rem; padding: 0.75rem 1rem; border-right: 1px solid var(--wire-color-border); color: var(--wire-color-on-primary); background: var(--wire-color-primary); font-size: 0.875rem; font-weight: 700; }
|
||||||
|
.wire-marquee__window { position: relative; min-width: 0; flex: 1; overflow: hidden; }
|
||||||
|
.wire-marquee__track {
|
||||||
|
display: flex; width: max-content; min-width: 100%; align-items: center;
|
||||||
animation: wire-marquee 32s linear infinite;
|
animation: wire-marquee 32s linear infinite;
|
||||||
}
|
}
|
||||||
|
.wire-marquee-paused { animation-play-state: paused; }
|
||||||
|
.wire-marquee__item { display: flex; flex: none; align-items: center; gap: 0.75rem; padding: 0.75rem 1.25rem; color: var(--wire-color-text); font-size: 0.875rem; font-weight: 500; transition: color var(--wire-motion-base), background var(--wire-motion-base); }
|
||||||
|
.wire-marquee__item:hover { color: var(--wire-color-primary); background: var(--wire-color-primary-soft); }
|
||||||
|
.wire-marquee__item:focus-visible, .wire-marquee__toggle:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: -2px; }
|
||||||
|
.wire-marquee__dot { width: 0.5rem; height: 0.5rem; flex: none; border-radius: 50%; background: var(--wire-color-primary); }
|
||||||
|
.wire-marquee__dot[data-color="danger"] { background: var(--wire-color-danger); }
|
||||||
|
.wire-marquee__dot[data-color="warning"] { background: var(--wire-color-warning); }
|
||||||
|
.wire-marquee__dot[data-color="success"] { background: var(--wire-color-success); }
|
||||||
|
.wire-marquee__meta { color: var(--wire-color-text-muted); font-size: 0.75rem; }
|
||||||
|
.wire-marquee__empty { padding: 0.75rem 1.25rem; color: var(--wire-color-text-muted); font-size: 0.875rem; }
|
||||||
|
.wire-marquee__toggle { display: flex; flex: none; align-items: center; justify-content: center; padding-inline: 1rem; border: 0; border-left: 1px solid var(--wire-color-border); color: var(--wire-color-text-muted); background: transparent; transition: color var(--wire-motion-base), background var(--wire-motion-base); }
|
||||||
|
.wire-marquee__toggle:hover { color: var(--wire-color-text); background: var(--wire-color-surface-soft); }
|
||||||
|
.wire-marquee__icon { width: 1rem; height: 1rem; }
|
||||||
|
@media (min-width: 40rem) { .wire-marquee__title { padding-inline: 1.25rem; } }
|
||||||
|
|
||||||
.wire-marquee-paused {
|
.wire-marquee-paused {
|
||||||
animation-play-state: paused;
|
animation-play-state: paused;
|
||||||
@@ -109,7 +126,7 @@ component Marquee {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.wire-marquee-track {
|
.wire-marquee__track {
|
||||||
animation: none;
|
animation: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,19 +26,19 @@ component SearchBox {
|
|||||||
<form
|
<form
|
||||||
data-ui-component="SearchBox"
|
data-ui-component="SearchBox"
|
||||||
role="search"
|
role="search"
|
||||||
class='w-full {class}'
|
class='wire-search-box {class}'
|
||||||
@submit='event.preventDefault(); output.search({ value: query, name: name })'
|
@submit='event.preventDefault(); output.search({ value: query, name: name })'
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="mb-2 block text-sm font-semibold text-[var(--wire-color-text)]"
|
class="wire-search-box__label"
|
||||||
class:sr-only='label === ""'
|
data-hidden='{label === "" ? "true" : "false"}'
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="relative flex items-center">
|
<div class="wire-search-box__control">
|
||||||
<span
|
<span
|
||||||
class="icon-[lucide--search] pointer-events-none absolute left-4 size-5 text-[var(--wire-color-input-placeholder)]"
|
class="icon-[lucide--search] wire-search-box__search-icon"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></span>
|
></span>
|
||||||
|
|
||||||
@@ -53,10 +53,8 @@ component SearchBox {
|
|||||||
disabled='{disabled}'
|
disabled='{disabled}'
|
||||||
required='{required}'
|
required='{required}'
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="w-full rounded-xl border border-[var(--wire-color-input-border)] bg-[var(--wire-color-input-background)] pl-12 pr-24 text-[var(--wire-color-input-text)] outline-none transition placeholder:text-[var(--wire-color-input-placeholder)] hover:border-[var(--wire-color-input-border-hover)] focus:border-[var(--wire-color-input-border-focus)] focus:ring-2 focus:ring-[var(--wire-color-focus)] disabled:cursor-not-allowed disabled:opacity-60"
|
class="wire-search-box__input"
|
||||||
class:h-10='size === "sm"'
|
data-size='{size}'
|
||||||
class:h-12='size === "default" || size === "md"'
|
|
||||||
class:h-14='size === "lg"'
|
|
||||||
@input='query = event.target.value'
|
@input='query = event.target.value'
|
||||||
@change='query = event.target.value'
|
@change='query = event.target.value'
|
||||||
/>
|
/>
|
||||||
@@ -65,21 +63,88 @@ component SearchBox {
|
|||||||
type="button"
|
type="button"
|
||||||
aria-label="Clear search"
|
aria-label="Clear search"
|
||||||
data-show='query.length > 0 && !disabled'
|
data-show='query.length > 0 && !disabled'
|
||||||
class="absolute right-12 inline-flex size-8 items-center justify-center rounded-lg text-[var(--wire-color-text-muted)] transition hover:bg-[var(--wire-color-surface-soft)] hover:text-[var(--wire-color-text)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)]"
|
class="wire-search-box__button wire-search-box__clear"
|
||||||
@click='query = ""; event.currentTarget.parentElement.querySelector("input")?.focus(); output.clear({ value: "", name: name })'
|
@click='query = ""; event.currentTarget.parentElement.querySelector("input")?.focus(); output.clear({ value: "", name: name })'
|
||||||
>
|
>
|
||||||
<span class="icon-[lucide--x] size-4" aria-hidden="true"></span>
|
<span class="icon-[lucide--x] wire-search-box__button-icon" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
aria-label='{label || "Search"}'
|
aria-label='{label || "Search"}'
|
||||||
disabled='{disabled}'
|
disabled='{disabled}'
|
||||||
class="absolute right-2 inline-flex size-9 items-center justify-center rounded-lg bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] transition hover:bg-[var(--wire-color-primary-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)] disabled:cursor-not-allowed disabled:opacity-60"
|
class="wire-search-box__button wire-search-box__submit"
|
||||||
>
|
>
|
||||||
<span class="icon-[lucide--arrow-right] size-4" aria-hidden="true"></span>
|
<span class="icon-[lucide--arrow-right] wire-search-box__button-icon" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
style {
|
||||||
|
.wire-search-box { width: 100%; }
|
||||||
|
.wire-search-box__label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: var(--wire-color-text);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.wire-search-box__label[data-hidden="true"] {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.wire-search-box__control { position: relative; display: flex; align-items: center; }
|
||||||
|
.wire-search-box__search-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 1rem;
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
color: var(--wire-color-input-placeholder);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.wire-search-box__input {
|
||||||
|
width: 100%;
|
||||||
|
height: 3rem;
|
||||||
|
padding: 0 6rem 0 3rem;
|
||||||
|
border: 1px solid var(--wire-color-input-border);
|
||||||
|
border-radius: var(--wire-radius);
|
||||||
|
outline: none;
|
||||||
|
color: var(--wire-color-input-text);
|
||||||
|
background: var(--wire-color-input-background);
|
||||||
|
transition: border-color var(--wire-motion-base) var(--wire-ease-standard), box-shadow var(--wire-motion-base) var(--wire-ease-standard);
|
||||||
|
}
|
||||||
|
.wire-search-box__input[data-size="sm"] { height: 2.5rem; }
|
||||||
|
.wire-search-box__input[data-size="lg"] { height: 3.5rem; }
|
||||||
|
.wire-search-box__input::placeholder { color: var(--wire-color-input-placeholder); }
|
||||||
|
.wire-search-box__input:hover { border-color: var(--wire-color-input-border-hover); }
|
||||||
|
.wire-search-box__input:focus {
|
||||||
|
border-color: var(--wire-color-input-border-focus);
|
||||||
|
box-shadow: 0 0 0 2px var(--wire-color-focus);
|
||||||
|
}
|
||||||
|
.wire-search-box__input:disabled, .wire-search-box__button:disabled { cursor: not-allowed; opacity: 0.6; }
|
||||||
|
.wire-search-box__button {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: var(--wire-radius-sm);
|
||||||
|
transition: color var(--wire-motion-base), background var(--wire-motion-base);
|
||||||
|
}
|
||||||
|
.wire-search-box__clear { right: 3rem; width: 2rem; height: 2rem; color: var(--wire-color-text-muted); background: transparent; }
|
||||||
|
.wire-search-box__clear:hover { color: var(--wire-color-text); background: var(--wire-color-surface-soft); }
|
||||||
|
.wire-search-box__submit { right: 0.5rem; width: 2.25rem; height: 2.25rem; color: var(--wire-color-on-primary); background: var(--wire-color-primary); }
|
||||||
|
.wire-search-box__submit:hover { background: var(--wire-color-primary-hover); }
|
||||||
|
.wire-search-box__button:focus-visible { outline: 2px solid var(--wire-color-focus); outline-offset: 2px; }
|
||||||
|
.wire-search-box__button-icon { width: 1rem; height: 1rem; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,18 +29,16 @@ label: string = "Learn more"
|
|||||||
data-size='{size}'
|
data-size='{size}'
|
||||||
data-color='{color}'
|
data-color='{color}'
|
||||||
data-variant='{variant}'
|
data-variant='{variant}'
|
||||||
class='inline-flex min-w-0 {class}'
|
class='wire-text-link {class}'
|
||||||
>
|
>
|
||||||
{#if disabled}
|
{#if disabled}
|
||||||
<span
|
<span
|
||||||
aria-disabled="true"
|
aria-disabled="true"
|
||||||
class="inline-flex cursor-not-allowed items-center gap-2 font-semibold opacity-50"
|
class="wire-text-link__control"
|
||||||
class:text-sm='size === "sm" || size === "default"'
|
data-size='{size}'
|
||||||
class:text-base='size === "md"'
|
|
||||||
class:text-lg='size === "lg"'
|
|
||||||
>
|
>
|
||||||
{#if icon && iconPosition === "start"}
|
{#if icon && iconPosition === "start"}
|
||||||
<span class='{icon + " size-4 shrink-0"}' aria-hidden="true"></span>
|
<span class='{icon + " wire-text-link__icon"}' aria-hidden="true"></span>
|
||||||
{/if}
|
{/if}
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
</span>
|
</span>
|
||||||
@@ -49,42 +47,82 @@ label: string = "Learn more"
|
|||||||
href='{href}'
|
href='{href}'
|
||||||
target='{target}'
|
target='{target}'
|
||||||
rel='{external ? (rel || "noopener noreferrer") : rel}'
|
rel='{external ? (rel || "noopener noreferrer") : rel}'
|
||||||
class="group inline-flex items-center gap-2 rounded-md font-semibold outline-none transition focus-visible:ring-2 focus-visible:ring-[var(--wire-color-focus)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--wire-color-background)]"
|
class="wire-text-link__control"
|
||||||
class:text-sm='size === "sm" || size === "default"'
|
data-size='{size}'
|
||||||
class:text-base='size === "md"'
|
data-color='{color}'
|
||||||
class:text-lg='size === "lg"'
|
data-variant='{variant}'
|
||||||
class:text-[var(--wire-color-primary)]='color === "primary"'
|
data-underline='{underline ? "true" : "false"}'
|
||||||
class:hover:text-[var(--wire-color-primary-hover)]='color === "primary"'
|
|
||||||
class:text-[var(--wire-color-secondary)]='color === "secondary"'
|
|
||||||
class:text-[var(--wire-color-success)]='color === "success"'
|
|
||||||
class:text-[var(--wire-color-warning-text)]='color === "warning"'
|
|
||||||
class:text-[var(--wire-color-danger)]='color === "danger"'
|
|
||||||
class:text-[var(--wire-color-info)]='color === "info"'
|
|
||||||
class:text-[var(--wire-color-text)]='color === "neutral"'
|
|
||||||
class:underline='underline'
|
|
||||||
class:underline-offset-4='underline'
|
|
||||||
class:rounded-lg='variant === "button"'
|
|
||||||
class:bg-[var(--wire-color-primary-soft)]='variant === "button" && color === "primary"'
|
|
||||||
class:px-3='variant === "button"'
|
|
||||||
class:py-2='variant === "button"'
|
|
||||||
>
|
>
|
||||||
{#if icon && iconPosition === "start"}
|
{#if icon && iconPosition === "start"}
|
||||||
<span class='{icon + " size-4 shrink-0"}' aria-hidden="true"></span>
|
<span class='{icon + " wire-text-link__icon"}' aria-hidden="true"></span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
|
|
||||||
{#if icon && iconPosition === "end"}
|
{#if icon && iconPosition === "end"}
|
||||||
<span class='{icon + " size-4 shrink-0"}' aria-hidden="true"></span>
|
<span class='{icon + " wire-text-link__icon"}' aria-hidden="true"></span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if external}
|
{#if external}
|
||||||
<span class="icon-[lucide--external-link] size-4 shrink-0" aria-hidden="true"></span>
|
<span class="icon-[lucide--external-link] wire-text-link__icon" aria-hidden="true"></span>
|
||||||
{:else if showArrow}
|
{:else if showArrow}
|
||||||
<span class="icon-[lucide--arrow-right] size-4 shrink-0 transition-transform group-hover:translate-x-1" aria-hidden="true"></span>
|
<span class="icon-[lucide--arrow-right] wire-text-link__icon wire-text-link__arrow" aria-hidden="true"></span>
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
style {
|
||||||
|
.wire-text-link {
|
||||||
|
display: inline-flex;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wire-text-link__control {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
border-radius: var(--wire-radius-sm);
|
||||||
|
color: var(--wire-color-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
outline: none;
|
||||||
|
transition: color var(--wire-motion-base) var(--wire-ease-standard);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.wire-text-link__control {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wire-text-link__control[data-size="sm"],
|
||||||
|
.wire-text-link__control[data-size="default"] { font-size: 0.875rem; }
|
||||||
|
.wire-text-link__control[data-size="md"] { font-size: 1rem; }
|
||||||
|
.wire-text-link__control[data-size="lg"] { font-size: 1.125rem; }
|
||||||
|
.wire-text-link__control[data-color="secondary"] { color: var(--wire-color-secondary); }
|
||||||
|
.wire-text-link__control[data-color="success"] { color: var(--wire-color-success); }
|
||||||
|
.wire-text-link__control[data-color="warning"] { color: var(--wire-color-warning-text); }
|
||||||
|
.wire-text-link__control[data-color="danger"] { color: var(--wire-color-danger); }
|
||||||
|
.wire-text-link__control[data-color="info"] { color: var(--wire-color-info); }
|
||||||
|
.wire-text-link__control[data-color="neutral"] { color: var(--wire-color-text); }
|
||||||
|
.wire-text-link__control[data-color="primary"]:hover { color: var(--wire-color-primary-hover); }
|
||||||
|
.wire-text-link__control[data-underline="true"] {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 0.25rem;
|
||||||
|
}
|
||||||
|
.wire-text-link__control[data-variant="button"] {
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
border-radius: var(--wire-radius);
|
||||||
|
}
|
||||||
|
.wire-text-link__control[data-variant="button"][data-color="primary"] {
|
||||||
|
background: var(--wire-color-primary-soft);
|
||||||
|
}
|
||||||
|
.wire-text-link__control:focus-visible {
|
||||||
|
outline: 2px solid var(--wire-color-focus);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
.wire-text-link__icon { width: 1rem; height: 1rem; flex: none; }
|
||||||
|
.wire-text-link__arrow { transition: transform var(--wire-motion-base) var(--wire-ease-standard); }
|
||||||
|
.wire-text-link__control:hover .wire-text-link__arrow { transform: translateX(0.25rem); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,71 +17,98 @@ component Timeline {
|
|||||||
<section
|
<section
|
||||||
data-ui-component="Timeline"
|
data-ui-component="Timeline"
|
||||||
aria-label='{title}'
|
aria-label='{title}'
|
||||||
class='w-full {class}'
|
class='wire-timeline {class}'
|
||||||
>
|
>
|
||||||
{#if title || description}
|
{#if title || description}
|
||||||
<header class="mb-6">
|
<header class="wire-timeline__header">
|
||||||
{#if title}
|
{#if title}
|
||||||
<h3 class="text-xl font-bold text-[var(--wire-color-text)]">{title}</h3>
|
<h3 class="wire-timeline__title">{title}</h3>
|
||||||
{/if}
|
{/if}
|
||||||
{#if description}
|
{#if description}
|
||||||
<p class="mt-2 max-w-2xl leading-7 text-[var(--wire-color-text-muted)]">{description}</p>
|
<p class="wire-timeline__description">{description}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</header>
|
</header>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<ol class="relative ml-4 border-l border-[var(--wire-color-border)]">
|
<ol class="wire-timeline__list">
|
||||||
{#each items as item, index}
|
{#each items as item, index}
|
||||||
<li
|
<li
|
||||||
class="relative pb-8 pl-8 last:pb-0"
|
class="wire-timeline__item"
|
||||||
@click='output.select({ item: item, index: index })'
|
@click='output.select({ item: item, index: index })'
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="absolute -left-[1.05rem] top-0 flex size-8 items-center justify-center rounded-full border-4 border-[var(--wire-color-background)] bg-[var(--wire-color-primary)] text-[var(--wire-color-on-primary)] shadow-sm"
|
class="wire-timeline__marker"
|
||||||
class:bg-[var(--wire-color-success)]='item.status === "complete" || item.status === "success"'
|
data-status='{item.status || "default"}'
|
||||||
class:bg-[var(--wire-color-warning)]='item.status === "warning" || item.status === "pending"'
|
|
||||||
class:bg-[var(--wire-color-danger)]='item.status === "danger" || item.status === "failed"'
|
|
||||||
>
|
>
|
||||||
<span class='{item.icon || "icon-[lucide--circle]"}' aria-hidden="true"></span>
|
<span class='{item.icon || "icon-[lucide--circle]"}' aria-hidden="true"></span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<article
|
<article
|
||||||
class="rounded-2xl border border-[var(--wire-color-border)] bg-[var(--wire-color-surface-raised)] p-5 shadow-sm"
|
class="wire-timeline__card"
|
||||||
class:border-transparent='variant === "minimal"'
|
data-variant='{variant}'
|
||||||
class:bg-transparent='variant === "minimal"'
|
|
||||||
class:p-0='variant === "minimal"'
|
|
||||||
class:shadow-none='variant === "minimal"'
|
|
||||||
>
|
>
|
||||||
<div class="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
|
<div class="wire-timeline__card-header">
|
||||||
<div>
|
<div>
|
||||||
<h4 class="font-bold text-[var(--wire-color-text)]">{item.title || item.label}</h4>
|
<h4 class="wire-timeline__item-title">{item.title || item.label}</h4>
|
||||||
{#if item.subtitle}
|
{#if item.subtitle}
|
||||||
<p class="mt-1 text-sm font-medium text-[var(--wire-color-primary)]">{item.subtitle}</p>
|
<p class="wire-timeline__subtitle">{item.subtitle}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if item.date || item.meta}
|
{#if item.date || item.meta}
|
||||||
<time class="shrink-0 text-sm text-[var(--wire-color-text-muted)]">{item.date || item.meta}</time>
|
<time class="wire-timeline__time">{item.date || item.meta}</time>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if item.description}
|
{#if item.description}
|
||||||
<p class="mt-3 text-sm leading-6 text-[var(--wire-color-text-muted)]">{item.description}</p>
|
<p class="wire-timeline__copy">{item.description}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if item.href}
|
{#if item.href}
|
||||||
<a href='{item.href}' class="mt-4 inline-flex items-center gap-2 text-sm font-semibold text-[var(--wire-color-primary)] hover:text-[var(--wire-color-primary-hover)]">
|
<a href='{item.href}' class="wire-timeline__action">
|
||||||
<span>{item.actionLabel || "View details"}</span>
|
<span>{item.actionLabel || "View details"}</span>
|
||||||
<span class="icon-[lucide--arrow-right] size-4" aria-hidden="true"></span>
|
<span class="icon-[lucide--arrow-right] wire-timeline__action-icon" aria-hidden="true"></span>
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</article>
|
</article>
|
||||||
</li>
|
</li>
|
||||||
{:empty}
|
{:empty}
|
||||||
<li class="pl-8 text-sm text-[var(--wire-color-text-muted)]">No timeline items available.</li>
|
<li class="wire-timeline__empty">No timeline items available.</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
style {
|
||||||
|
.wire-timeline { width: 100%; }
|
||||||
|
.wire-timeline__header { margin-bottom: 1.5rem; }
|
||||||
|
.wire-timeline__title { color: var(--wire-color-text); font-size: 1.25rem; font-weight: 700; }
|
||||||
|
.wire-timeline__description { max-width: 42rem; margin-top: 0.5rem; color: var(--wire-color-text-muted); line-height: 1.75rem; }
|
||||||
|
.wire-timeline__list { position: relative; margin-left: 1rem; border-left: 1px solid var(--wire-color-border); }
|
||||||
|
.wire-timeline__item { position: relative; padding: 0 0 2rem 2rem; cursor: pointer; }
|
||||||
|
.wire-timeline__item:last-child { padding-bottom: 0; }
|
||||||
|
.wire-timeline__marker {
|
||||||
|
position: absolute; top: 0; left: -1.05rem; display: flex; width: 2rem; height: 2rem;
|
||||||
|
align-items: center; justify-content: center; border: 4px solid var(--wire-color-background);
|
||||||
|
border-radius: 50%; color: var(--wire-color-on-primary); background: var(--wire-color-primary); box-shadow: var(--wire-shadow-1);
|
||||||
|
}
|
||||||
|
.wire-timeline__marker:is([data-status="complete"], [data-status="success"]) { background: var(--wire-color-success); }
|
||||||
|
.wire-timeline__marker:is([data-status="warning"], [data-status="pending"]) { background: var(--wire-color-warning); }
|
||||||
|
.wire-timeline__marker:is([data-status="danger"], [data-status="failed"]) { background: var(--wire-color-danger); }
|
||||||
|
.wire-timeline__card { padding: 1.25rem; border: 1px solid var(--wire-color-border); border-radius: calc(var(--wire-radius) * 1.5); background: var(--wire-color-surface-raised); box-shadow: var(--wire-shadow-1); }
|
||||||
|
.wire-timeline__card[data-variant="minimal"] { padding: 0; border-color: transparent; background: transparent; box-shadow: none; }
|
||||||
|
.wire-timeline__card-header { display: flex; flex-direction: column; gap: 0.5rem; }
|
||||||
|
.wire-timeline__item-title { color: var(--wire-color-text); font-weight: 700; }
|
||||||
|
.wire-timeline__subtitle { margin-top: 0.25rem; color: var(--wire-color-primary); font-size: 0.875rem; font-weight: 500; }
|
||||||
|
.wire-timeline__time { flex: none; color: var(--wire-color-text-muted); font-size: 0.875rem; }
|
||||||
|
.wire-timeline__copy { margin-top: 0.75rem; color: var(--wire-color-text-muted); font-size: 0.875rem; line-height: 1.5rem; }
|
||||||
|
.wire-timeline__action { display: inline-flex; align-items: center; gap: 0.5rem; margin-top: 1rem; color: var(--wire-color-primary); font-size: 0.875rem; font-weight: 600; }
|
||||||
|
.wire-timeline__action:hover { color: var(--wire-color-primary-hover); }
|
||||||
|
.wire-timeline__action-icon { width: 1rem; height: 1rem; }
|
||||||
|
.wire-timeline__empty { padding-left: 2rem; color: var(--wire-color-text-muted); font-size: 0.875rem; }
|
||||||
|
@media (min-width: 40rem) {
|
||||||
|
.wire-timeline__card-header { flex-direction: row; align-items: flex-start; justify-content: space-between; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3080,6 +3080,25 @@ test("layout components ship their own styles instead of Tailwind utilities", ()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("remaining utility-styled components use local BEM styles", () => {
|
||||||
|
const migrated = ["List", "InputNumber", "Marquee", "TextLink", "Map", "SearchBox", "Timeline"];
|
||||||
|
const utilityMarkup =
|
||||||
|
/class(?::[^=\s]+)?=['"][^'"]*\b(?:flex|grid|w-full|items-center|justify-between|gap-[0-9]|p[xytrbl]?-[0-9]|m[xytrbl]?-[0-9]|text-(?:xs|sm|lg|xl)|rounded-(?:md|lg|xl|2xl|full)|border-[lrtbxy]?|bg-\[|shadow-(?:sm|lg)|size-[0-9])\b/;
|
||||||
|
|
||||||
|
for (const name of migrated) {
|
||||||
|
const source = readFileSync(uiComponentPath(name), "utf8");
|
||||||
|
const markup = source.split(/^\s{2,4}style \{/m)[0] ?? source;
|
||||||
|
expect({ name, hasStyleBlock: /^\s{2,4}style \{/m.test(source) }).toEqual({
|
||||||
|
name,
|
||||||
|
hasStyleBlock: true,
|
||||||
|
});
|
||||||
|
expect({ name, utilityMarkup: utilityMarkup.test(markup) }).toEqual({
|
||||||
|
name,
|
||||||
|
utilityMarkup: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("every wire color token a component references is defined by the theme", () => {
|
test("every wire color token a component references is defined by the theme", () => {
|
||||||
/*
|
/*
|
||||||
* Ten tokens were referenced by components and defined by nothing:
|
* Ten tokens were referenced by components and defined by nothing:
|
||||||
@@ -3179,6 +3198,25 @@ test("no component gains an output that nothing ever emits", () => {
|
|||||||
expect(offenders).not.toContain("CustomScrollbar.scroll");
|
expect(offenders).not.toContain("CustomScrollbar.scroll");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("list selects items without hrefs as well as navigation items", async () => {
|
||||||
|
const source = readFileSync(uiComponentPath("List"), "utf8");
|
||||||
|
const dom = mountHtml(
|
||||||
|
await renderComponent(source, {
|
||||||
|
title: "Actions",
|
||||||
|
items: [{ label: "Run report" }],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const root = dom.querySelector('[data-ui-component="List"]') as HTMLElement;
|
||||||
|
const events: Array<{ item: { label: string }; index: number }> = [];
|
||||||
|
root.addEventListener("select", (event) => {
|
||||||
|
events.push((event as CustomEvent).detail);
|
||||||
|
});
|
||||||
|
|
||||||
|
(root.querySelector("li") as HTMLElement).click();
|
||||||
|
|
||||||
|
expect(events).toEqual([{ item: { label: "Run report" }, index: 0 }]);
|
||||||
|
});
|
||||||
|
|
||||||
test("a declared output is never emitted as a hand-built CustomEvent", () => {
|
test("a declared output is never emitted as a hand-built CustomEvent", () => {
|
||||||
/*
|
/*
|
||||||
* The failure this prevents is silent in both directions: the component
|
* The failure this prevents is silent in both directions: the component
|
||||||
|
|||||||
Reference in New Issue
Block a user