Updated Complete Tailwindcss Classes
This commit is contained in:
+56
-55
@@ -35,100 +35,101 @@ const {
|
||||
}: Props = Astro.props;
|
||||
|
||||
const base =
|
||||
"inline-flex items-center justify-center gap-2 font-medium transition-colors " +
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 " +
|
||||
"disabled:opacity-50 disabled:pointer-events-none";
|
||||
"wr:inline-flex wr:items-center wr:justify-center wr:gap-2 wr:font-medium wr:transition-colors " +
|
||||
"wr:focus-visible:outline-none wr:focus-visible:ring-2 wr:focus-visible:ring-offset-2 " +
|
||||
"wr:disabled:opacity-50 wr:disabled:pointer-events-none";
|
||||
|
||||
const sizeClass: Record<Size, string> = {
|
||||
sm: "h-8 px-3 text-sm",
|
||||
md: "h-10 px-4 text-sm",
|
||||
lg: "h-11 px-5 text-base",
|
||||
icon: "h-10 w-10 p-0",
|
||||
sm: "wr:h-8 wr:px-3 wr:text-sm",
|
||||
md: "wr:h-10 wr:px-4 wr:text-sm",
|
||||
lg: "wr:h-11 wr:px-5 wr:text-base",
|
||||
icon: "wr:h-10 wr:w-10 wr:p-0",
|
||||
};
|
||||
|
||||
const radius = pill ? "rounded-full" : "rounded-md";
|
||||
const radius = pill ? "wr:rounded-full" : "wr:rounded-md";
|
||||
|
||||
const styles: Record<Color, Record<Variant, string>> = {
|
||||
primary: {
|
||||
solid: "bg-primary text-primary-foreground hover:bg-primary/90 border border-transparent focus-visible:ring-primary/40",
|
||||
solid: "wr:bg-primary wr:text-primary-foreground wr:hover:bg-primary/90 wr:border wr:border-transparent wr:focus-visible:ring-primary/40",
|
||||
outline:
|
||||
"border border-primary text-primary hover:bg-primary/10 focus-visible:ring-primary/40",
|
||||
ghost: "text-primary hover:bg-primary/10 border border-transparent focus-visible:ring-primary/30",
|
||||
soft: "bg-primary/15 text-primary hover:bg-primary/20 border border-transparent focus-visible:ring-primary/30",
|
||||
link: "text-primary underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-primary/40",
|
||||
"wr:border wr:border-primary wr:text-primary wr:hover:bg-primary/10 wr:focus-visible:ring-primary/40",
|
||||
ghost: "wr:text-primary wr:hover:bg-primary/10 wr:border wr:border-transparent wr:focus-visible:ring-primary/30",
|
||||
soft: "wr:bg-primary/15 wr:text-primary wr:hover:bg-primary/20 wr:border wr:border-transparent wr:focus-visible:ring-primary/30",
|
||||
link: "wr:text-primary wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-primary/40",
|
||||
},
|
||||
secondary: {
|
||||
solid: "bg-secondary text-secondary-foreground hover:bg-secondary/90 border border-transparent focus-visible:ring-secondary/40",
|
||||
solid: "wr:bg-secondary wr:text-secondary-foreground wr:hover:bg-secondary/90 wr:border wr:border-transparent wr:focus-visible:ring-secondary/40",
|
||||
outline:
|
||||
"border border-secondary text-secondary hover:bg-secondary/10 focus-visible:ring-secondary/40",
|
||||
ghost: "text-secondary hover:bg-secondary/10 border border-transparent focus-visible:ring-secondary/30",
|
||||
soft: "bg-secondary/15 text-secondary hover:bg-secondary/20 border border-transparent focus-visible:ring-secondary/30",
|
||||
link: "text-secondary underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-secondary/40",
|
||||
"wr:border wr:border-secondary wr:text-secondary wr:hover:bg-secondary/10 wr:focus-visible:ring-secondary/40",
|
||||
ghost: "wr:text-secondary wr:hover:bg-secondary/10 wr:border wr:border-transparent wr:focus-visible:ring-secondary/30",
|
||||
soft: "wr:bg-secondary/15 wr:text-secondary wr:hover:bg-secondary/20 wr:border wr:border-transparent wr:focus-visible:ring-secondary/30",
|
||||
link: "wr:text-secondary wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-secondary/40",
|
||||
},
|
||||
tertiary: {
|
||||
solid: "bg-tertiary text-tertiary-foreground hover:bg-tertiary/90 border border-transparent focus-visible:ring-tertiary/40",
|
||||
solid: "wr:bg-tertiary wr:text-tertiary-foreground wr:hover:bg-tertiary/90 wr:border wr:border-transparent wr:focus-visible:ring-tertiary/40",
|
||||
outline:
|
||||
"border border-tertiary text-tertiary hover:bg-tertiary/10 focus-visible:ring-tertiary/40",
|
||||
ghost: "text-tertiary hover:bg-tertiary/10 border border-transparent focus-visible:ring-tertiary/30",
|
||||
soft: "bg-tertiary/15 text-tertiary hover:bg-tertiary/20 border border-transparent focus-visible:ring-tertiary/30",
|
||||
link: "text-tertiary underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-tertiary/40",
|
||||
"wr:border wr:border-tertiary wr:text-tertiary wr:hover:bg-tertiary/10 wr:focus-visible:ring-tertiary/40",
|
||||
ghost: "wr:text-tertiary wr:hover:bg-tertiary/10 wr:border wr:border-transparent wr:focus-visible:ring-tertiary/30",
|
||||
soft: "wr:bg-tertiary/15 wr:text-tertiary wr:hover:bg-tertiary/20 wr:border wr:border-transparent wr:focus-visible:ring-tertiary/30",
|
||||
link: "wr:text-tertiary wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-tertiary/40",
|
||||
},
|
||||
accent: {
|
||||
solid: "bg-accent text-accent-foreground hover:bg-accent/90 border border-transparent focus-visible:ring-accent/40",
|
||||
solid: "wr:bg-accent wr:text-accent-foreground wr:hover:bg-accent/90 wr:border wr:border-transparent wr:focus-visible:ring-accent/40",
|
||||
outline:
|
||||
"border border-accent text-accent hover:bg-accent/10 focus-visible:ring-accent/40",
|
||||
ghost: "text-accent hover:bg-accent/10 border border-transparent focus-visible:ring-accent/30",
|
||||
soft: "bg-accent/15 text-accent hover:bg-accent/20 border border-transparent focus-visible:ring-accent/30",
|
||||
link: "text-accent underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-accent/40",
|
||||
"wr:border wr:border-accent wr:text-accent wr:hover:bg-accent/10 wr:focus-visible:ring-accent/40",
|
||||
ghost: "wr:text-accent wr:hover:bg-accent/10 wr:border wr:border-transparent wr:focus-visible:ring-accent/30",
|
||||
soft: "wr:bg-accent/15 wr:text-accent wr:hover:bg-accent/20 wr:border wr:border-transparent wr:focus-visible:ring-accent/30",
|
||||
link: "wr:text-accent wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-accent/40",
|
||||
},
|
||||
info: {
|
||||
solid: "bg-info text-info-foreground hover:bg-info/90 border border-transparent focus-visible:ring-info/40",
|
||||
solid: "wr:bg-info wr:text-info-foreground wr:hover:bg-info/90 wr:border wr:border-transparent wr:focus-visible:ring-info/40",
|
||||
outline:
|
||||
"border border-info text-info hover:bg-info/10 focus-visible:ring-info/40",
|
||||
ghost: "text-info hover:bg-info/10 border border-transparent focus-visible:ring-info/30",
|
||||
soft: "bg-info/15 text-info hover:bg-info/20 border border-transparent focus-visible:ring-info/30",
|
||||
link: "text-info underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-info/40",
|
||||
"wr:border wr:border-info wr:text-info wr:hover:bg-info/10 wr:focus-visible:ring-info/40",
|
||||
ghost: "wr:text-info wr:hover:bg-info/10 wr:border wr:border-transparent wr:focus-visible:ring-info/30",
|
||||
soft: "wr:bg-info/15 wr:text-info wr:hover:bg-info/20 wr:border wr:border-transparent wr:focus-visible:ring-info/30",
|
||||
link: "wr:text-info wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-info/40",
|
||||
},
|
||||
success: {
|
||||
solid: "bg-success text-success-foreground hover:bg-success/90 border border-transparent focus-visible:ring-success/40",
|
||||
solid: "wr:bg-success wr:text-success-foreground wr:hover:bg-success/90 wr:border wr:border-transparent wr:focus-visible:ring-success/40",
|
||||
outline:
|
||||
"border border-success text-success hover:bg-success/10 focus-visible:ring-success/40",
|
||||
ghost: "text-success hover:bg-success/10 border border-transparent focus-visible:ring-success/30",
|
||||
soft: "bg-success/15 text-success hover:bg-success/20 border border-transparent focus-visible:ring-success/30",
|
||||
link: "text-success underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-success/40",
|
||||
"wr:border wr:border-success wr:text-success wr:hover:bg-success/10 wr:focus-visible:ring-success/40",
|
||||
ghost: "wr:text-success wr:hover:bg-success/10 wr:border wr:border-transparent wr:focus-visible:ring-success/30",
|
||||
soft: "wr:bg-success/15 wr:text-success wr:hover:bg-success/20 wr:border wr:border-transparent wr:focus-visible:ring-success/30",
|
||||
link: "wr:text-success wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-success/40",
|
||||
},
|
||||
warning: {
|
||||
solid: "bg-warning text-warning-foreground hover:bg-warning/90 border border-transparent focus-visible:ring-warning/40",
|
||||
solid: "wr:bg-warning wr:text-warning-foreground wr:hover:bg-warning/90 wr:border wr:border-transparent wr:focus-visible:ring-warning/40",
|
||||
outline:
|
||||
"border border-warning text-warning hover:bg-warning/10 focus-visible:ring-warning/40",
|
||||
ghost: "text-warning hover:bg-warning/10 border border-transparent focus-visible:ring-warning/30",
|
||||
soft: "bg-warning/14 text-warning hover:bg-warning/20 border border-transparent focus-visible:ring-warning/30",
|
||||
link: "text-warning underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-warning/40",
|
||||
"wr:border wr:border-warning wr:text-warning wr:hover:bg-warning/10 wr:focus-visible:ring-warning/40",
|
||||
ghost: "wr:text-warning wr:hover:bg-warning/10 wr:border wr:border-transparent wr:focus-visible:ring-warning/30",
|
||||
soft: "wr:bg-warning/14 wr:text-warning wr:hover:bg-warning/20 wr:border wr:border-transparent wr:focus-visible:ring-warning/30",
|
||||
link: "wr:text-warning wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-warning/40",
|
||||
},
|
||||
danger: {
|
||||
solid: "bg-danger text-danger-foreground hover:bg-danger/90 border border-transparent focus-visible:ring-danger/40",
|
||||
solid: "wr:bg-danger wr:text-danger-foreground wr:hover:bg-danger/90 wr:border wr:border-transparent wr:focus-visible:ring-danger/40",
|
||||
outline:
|
||||
"border border-danger text-danger hover:bg-danger/10 focus-visible:ring-danger/40",
|
||||
ghost: "text-danger hover:bg-danger/10 border border-transparent focus-visible:ring-danger/30",
|
||||
soft: "bg-danger/15 text-danger hover:bg-danger/20 border border-transparent focus-visible:ring-danger/30",
|
||||
link: "text-danger underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-danger/40",
|
||||
"wr:border wr:border-danger wr:text-danger wr:hover:bg-danger/10 wr:focus-visible:ring-danger/40",
|
||||
ghost: "wr:text-danger wr:hover:bg-danger/10 wr:border wr:border-transparent wr:focus-visible:ring-danger/30",
|
||||
soft: "wr:bg-danger/15 wr:text-danger wr:hover:bg-danger/20 wr:border wr:border-transparent wr:focus-visible:ring-danger/30",
|
||||
link: "wr:text-danger wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-danger/40",
|
||||
},
|
||||
neutral: {
|
||||
solid: "bg-neutral text-neutral-foreground hover:bg-neutral/90 border border-transparent focus-visible:ring-neutral/40",
|
||||
solid: "wr:bg-neutral wr:text-neutral-foreground wr:hover:bg-neutral/90 wr:border wr:border-transparent wr:focus-visible:ring-neutral/40",
|
||||
outline:
|
||||
"border border-neutral text-neutral hover:bg-neutral/10 focus-visible:ring-neutral/40",
|
||||
ghost: "text-neutral hover:bg-neutral/10 border border-transparent focus-visible:ring-neutral/30",
|
||||
soft: "bg-neutral/15 text-neutral hover:bg-neutral/20 border border-transparent focus-visible:ring-neutral/30",
|
||||
link: "text-neutral underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-neutral/40",
|
||||
"wr:border wr:border-neutral wr:text-neutral wr:hover:bg-neutral/10 wr:focus-visible:ring-neutral/40",
|
||||
ghost: "wr:text-neutral wr:hover:bg-neutral/10 wr:border wr:border-transparent wr:focus-visible:ring-neutral/30",
|
||||
soft: "wr:bg-neutral/15 wr:text-neutral wr:hover:bg-neutral/20 wr:border wr:border-transparent wr:focus-visible:ring-neutral/30",
|
||||
link: "wr:text-neutral wr:underline wr:underline-offset-4 wr:p-0 wr:h-auto wr:border-0 wr:focus-visible:ring-neutral/40",
|
||||
},
|
||||
};
|
||||
|
||||
const variantColor = styles[color][variant];
|
||||
const sizeKls = variant === "link" ? "" : sizeClass[size];
|
||||
const iconSize = size === "sm" ? "size-4" : size === "lg" ? "size-5" : "size-5";
|
||||
const iconSize =
|
||||
size === "sm" ? "wr:size-4" : size === "lg" ? "wr:size-5" : "wr:size-5";
|
||||
---
|
||||
|
||||
<button class={cn(base, radius, sizeKls, variantColor, className)} {...rest}>
|
||||
{icon && <Icon name={icon} class={cn(iconSize, "shrink-0")} />}
|
||||
{icon && <Icon name={icon} class={cn(iconSize, "wr:shrink-0")} />}
|
||||
<slot />
|
||||
</button>
|
||||
|
||||
+76
-63
@@ -53,47 +53,48 @@ const descId = p.description ? `${fieldId}-desc` : undefined;
|
||||
const errId = `${fieldId}-err`;
|
||||
|
||||
const inputBase = cva(
|
||||
"py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg sm:text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600",
|
||||
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
sm: "h-10 px-3 text-sm",
|
||||
md: "h-11 px-3 text-sm",
|
||||
lg: "h-12 px-4 text-base",
|
||||
sm: "wr:h-10 wr:px-3 wr:text-sm",
|
||||
md: "wr:h-11 wr:px-3 wr:text-sm",
|
||||
lg: "wr:h-12 wr:px-4 wr:text-base",
|
||||
},
|
||||
withIconLeft: { true: "pl-10" },
|
||||
withIconRight: { true: "pr-10" },
|
||||
withIconLeft: { true: "wr:pl-10" },
|
||||
withIconRight: { true: "wr:pr-10" },
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const selectBase = cva(
|
||||
"py-3 px-4 pe-9 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600",
|
||||
"wr:py-3 wr:px-4 wr:pe-9 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
sm: "h-10 px-3 text-sm",
|
||||
md: "h-11 px-3 text-sm",
|
||||
lg: "h-12 px-4 text-base",
|
||||
sm: "wr:h-10 wr:px-3 wr:text-sm",
|
||||
md: "wr:h-11 wr:px-3 wr:text-sm",
|
||||
lg: "wr:h-12 wr:px-4 wr:text-base",
|
||||
},
|
||||
withIconLeft: { true: "pl-10" },
|
||||
withIconRight: { true: "pr-10" },
|
||||
withIconLeft: { true: "wr:pl-10" },
|
||||
withIconRight: { true: "wr:pr-10" },
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const iconSize =
|
||||
p.size === "sm" ? "size-4" : p.size === "lg" ? "size-5" : "size-5";
|
||||
const labelCls = "block text-sm font-medium mb-2 dark:text-white";
|
||||
const helpCls = "mt-2 text-sm text-gray-500 dark:text-neutral-500";
|
||||
const errCls = "text-sm text-red-600 mt-2";
|
||||
const groupCls = "relative flex items-stretch";
|
||||
p.size === "sm" ? "wr:size-4" : p.size === "lg" ? "wr:size-5" : "wr:size-5";
|
||||
const labelCls =
|
||||
"wr:block wr:text-sm wr:font-medium wr:mb-2 wr:dark:text-white";
|
||||
const helpCls = "wr:mt-2 wr:text-sm wr:text-gray-500 wr:dark:text-neutral-500";
|
||||
const errCls = "wr:text-sm wr:text-red-600 wr:mt-2";
|
||||
const groupCls = "wr:relative wr:flex wr:items-stretch";
|
||||
const addonBase =
|
||||
"px-4 inline-flex items-center min-w-fit rounded-md border border-gray-200 bg-gray-50 text-sm text-gray-500 dark:bg-neutral-700 dark:border-neutral-700 dark:text-neutral-400";
|
||||
const controlWrap = "relative";
|
||||
"wr:px-4 wr:inline-flex wr:items-center wr:min-w-fit wr:rounded-md wr:border wr:border-gray-200 wr:bg-gray-50 wr:text-sm wr:text-gray-500 wr:dark:bg-neutral-700 wr:dark:border-neutral-700 wr:dark:text-neutral-400";
|
||||
const controlWrap = "wr:relative";
|
||||
---
|
||||
|
||||
<div class={cn("space-y-1.5", p.class)} data-field={p.name}>
|
||||
<div class={cn("wr:space-y-1.5", p.class)} data-field={p.name}>
|
||||
{
|
||||
p.label &&
|
||||
[
|
||||
@@ -108,7 +109,8 @@ const controlWrap = "relative";
|
||||
"select",
|
||||
].includes(p.kind ?? "text") && (
|
||||
<label for={fieldId} class={labelCls}>
|
||||
{p.label} {p.required && <span class="text-danger">*</span>}
|
||||
{p.label}{" "}
|
||||
{p.required && <span class="wr:text-danger">*</span>}
|
||||
</label>
|
||||
)
|
||||
}
|
||||
@@ -119,14 +121,16 @@ const controlWrap = "relative";
|
||||
) && (
|
||||
<div class={groupCls}>
|
||||
{p.prefixText && (
|
||||
<span class={cn(addonBase, "border-r-0 rounded-r-none")}>
|
||||
<span
|
||||
class={cn(addonBase, "wr:border-r-0 wr:rounded-r-none")}
|
||||
>
|
||||
{p.prefixText}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<div class={cn(controlWrap, "flex-1")}>
|
||||
<div class={cn(controlWrap, "wr:flex-1")}>
|
||||
{p.iconLeft && (
|
||||
<span class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-muted-foreground">
|
||||
<span class="wr:absolute wr:inset-y-0 wr:left-0 wr:flex wr:items-center wr:pl-3 wr:pointer-events-none wr:text-muted-foreground">
|
||||
<Icon name={p.iconLeft} class={iconSize} />
|
||||
</span>
|
||||
)}
|
||||
@@ -142,10 +146,10 @@ const controlWrap = "relative";
|
||||
withIconRight:
|
||||
!!p.iconRight || p.kind === "password",
|
||||
}),
|
||||
p.prefixText && "rounded-l-none",
|
||||
p.suffixText && "rounded-r-none",
|
||||
p.prefixText && "wr:rounded-l-none",
|
||||
p.suffixText && "wr:rounded-r-none",
|
||||
p.error &&
|
||||
"border-danger focus-visible:ring-danger/40",
|
||||
"wr:border-danger wr:focus-visible:ring-danger/40",
|
||||
)}
|
||||
data-control
|
||||
placeholder={p.placeholder}
|
||||
@@ -168,7 +172,7 @@ const controlWrap = "relative";
|
||||
{p.kind === "password" && (
|
||||
<button
|
||||
type="button"
|
||||
class="absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground"
|
||||
class="wr:absolute wr:inset-y-0 wr:right-0 wr:pr-3 wr:flex wr:items-center wr:text-muted-foreground hover:wr:text-foreground"
|
||||
onclick={`const i = this.previousElementSibling; i.type = i.type === 'password' ? 'text' : 'password';`}
|
||||
>
|
||||
<Icon name="mdi:eye" class={iconSize} />
|
||||
@@ -176,14 +180,16 @@ const controlWrap = "relative";
|
||||
)}
|
||||
|
||||
{p.iconRight && (
|
||||
<span class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-muted-foreground">
|
||||
<span class="wr:absolute wr:inset-y-0 wr:right-0 wr:pr-3 wr:flex wr:items-center wr:pointer-events-none wr:text-muted-foreground">
|
||||
<Icon name={p.iconRight} class={iconSize} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{p.suffixText && (
|
||||
<span class={cn(addonBase, "border-l-0 rounded-l-none")}>
|
||||
<span
|
||||
class={cn(addonBase, "wr:border-l-0 wr:rounded-l-none")}
|
||||
>
|
||||
{p.suffixText}
|
||||
</span>
|
||||
)}
|
||||
@@ -195,14 +201,16 @@ const controlWrap = "relative";
|
||||
p.kind === "file" && (
|
||||
<div class={groupCls}>
|
||||
{p.prefixText && (
|
||||
<span class={cn(addonBase, "border-r-0 rounded-r-none")}>
|
||||
<span
|
||||
class={cn(addonBase, "wr:border-r-0 wr:rounded-r-none")}
|
||||
>
|
||||
{p.prefixText}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<div class={cn(controlWrap, "flex-1")}>
|
||||
<div class={cn(controlWrap, "wr:flex-1")}>
|
||||
{p.iconLeft && (
|
||||
<span class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-muted-foreground">
|
||||
<span class="wr:absolute wr:inset-y-0 wr:left-0 wr:flex wr:items-center wr:pl-3 wr:pointer-events-none wr:text-muted-foreground">
|
||||
<Icon name={p.iconLeft} class={iconSize} />
|
||||
</span>
|
||||
)}
|
||||
@@ -212,11 +220,11 @@ const controlWrap = "relative";
|
||||
name={p.name}
|
||||
type={(p.kind as any) ?? "text"}
|
||||
class={cn(
|
||||
"block w-full border border-gray-200 shadow-sm rounded-lg text-sm focus:z-10 focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 file:bg-gray-50 file:border-0 file:me-4 file:py-3 file:px-4 dark:file:bg-neutral-700 dark:file:text-neutral-400",
|
||||
p.prefixText && "rounded-l-none",
|
||||
p.suffixText && "rounded-r-none",
|
||||
"wr:block wr:w-full wr:border wr:border-gray-200 wr:shadow-sm wr:rounded-lg wr:text-sm wr:focus:z-10 wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:file:bg-gray-50 wr:file:border-0 wr:file:me-4 wr:file:py-3 wr:file:px-4 wr:dark:file:bg-neutral-700 wr:dark:file:text-neutral-400",
|
||||
p.prefixText && "wr:rounded-l-none",
|
||||
p.suffixText && "wr:rounded-r-none",
|
||||
p.error &&
|
||||
"border-danger focus-visible:ring-danger/40",
|
||||
"wr:border-danger wr:focus-visible:ring-danger/40",
|
||||
)}
|
||||
data-control
|
||||
multiple
|
||||
@@ -238,14 +246,16 @@ const controlWrap = "relative";
|
||||
/>
|
||||
|
||||
{p.iconRight && (
|
||||
<span class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-muted-foreground">
|
||||
<span class="wr:absolute wr:inset-y-0 wr:right-0 wr:pr-3 wr:flex wr:items-center wr:pointer-events-none wr:text-muted-foreground">
|
||||
<Icon name={p.iconRight} class={iconSize} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{p.suffixText && (
|
||||
<span class={cn(addonBase, "border-l-0 rounded-l-none")}>
|
||||
<span
|
||||
class={cn(addonBase, "wr:border-l-0 wr:rounded-l-none")}
|
||||
>
|
||||
{p.suffixText}
|
||||
</span>
|
||||
)}
|
||||
@@ -271,13 +281,14 @@ const controlWrap = "relative";
|
||||
.join(" ") || undefined
|
||||
}
|
||||
class={cn(
|
||||
"py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg sm:text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600",
|
||||
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
||||
p.size === "sm"
|
||||
? "text-sm p-3"
|
||||
? "wr:text-sm wr:p-3"
|
||||
: p.size === "lg"
|
||||
? "text-base p-4"
|
||||
: "text-sm p-3",
|
||||
p.error && "border-danger focus-visible:ring-danger/40",
|
||||
? "wr:text-base wr:p-4"
|
||||
: "wr:text-sm wr:p-3",
|
||||
p.error &&
|
||||
"wr:border-danger wr:focus-visible:ring-danger/40",
|
||||
)}
|
||||
data-initial={typeof p.value === "string" ? p.value : ""}
|
||||
/>
|
||||
@@ -303,8 +314,9 @@ const controlWrap = "relative";
|
||||
}
|
||||
class={cn(
|
||||
selectBase({ size: p.size ?? "md" }),
|
||||
"appearance-none bg-none pr-9",
|
||||
p.error && "border-danger focus-visible:ring-danger/40",
|
||||
"wr:appearance-none wr:bg-none wr:pr-9",
|
||||
p.error &&
|
||||
"wr:border-danger wr:focus-visible:ring-danger/40",
|
||||
)}
|
||||
>
|
||||
{!p.multiple && p.placeholder && (
|
||||
@@ -326,7 +338,7 @@ const controlWrap = "relative";
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<span class="pointer-events-none absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground">
|
||||
<span class="wr:pointer-events-none wr:absolute wr:inset-y-0 wr:right-0 wr:pr-3 wr:flex wr:items-center wr:text-muted-foreground">
|
||||
<Icon name="mdi:chevron-down" class={iconSize} />
|
||||
</span>
|
||||
</div>
|
||||
@@ -335,12 +347,12 @@ const controlWrap = "relative";
|
||||
|
||||
{
|
||||
p.kind === "checkbox" && (
|
||||
<label class="flex items-center gap-3">
|
||||
<label class="wr:flex wr:items-center wr:gap-3">
|
||||
<input
|
||||
id={fieldId}
|
||||
name={p.name}
|
||||
type="checkbox"
|
||||
class="shrink-0 mt-0.5 border-gray-200 rounded-sm text-blue-600 focus:ring-blue-500 checked:border-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800"
|
||||
class="wr:shrink-0 wr:mt-0.5 wr:border-gray-200 wr:rounded-sm wr:text-blue-600 wr:focus:ring-blue-500 wr:checked:border-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-800 wr:dark:border-neutral-700 wr:dark:checked:bg-blue-500 wr:dark:checked:border-blue-500 wr:dark:focus:ring-offset-gray-800"
|
||||
checked={!!p.value}
|
||||
disabled={p.disabled}
|
||||
data-control
|
||||
@@ -353,7 +365,9 @@ const controlWrap = "relative";
|
||||
/>
|
||||
<div>
|
||||
{p.label && (
|
||||
<span class="text-sm text-foreground">{p.label}</span>
|
||||
<span class="wr:text-sm wr:text-foreground">
|
||||
{p.label}
|
||||
</span>
|
||||
)}
|
||||
{p.description && (
|
||||
<p id={descId} class={helpCls}>
|
||||
@@ -367,25 +381,25 @@ const controlWrap = "relative";
|
||||
|
||||
{
|
||||
p.kind === "radio" && (
|
||||
<fieldset class="space-y-2">
|
||||
<fieldset class="wr:space-y-2">
|
||||
{p.label && (
|
||||
<legend class="text-sm font-medium text-foreground">
|
||||
<legend class="wr:text-sm wr:font-medium wr:text-foreground">
|
||||
{p.label}
|
||||
</legend>
|
||||
)}
|
||||
<div class="space-x-3">
|
||||
<div class="wr:space-x-3">
|
||||
{(p.options ?? []).map((opt) => (
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<label class="wr:inline-flex wr:items-center wr:gap-2">
|
||||
<input
|
||||
type="radio"
|
||||
name={p.name}
|
||||
value={opt.value}
|
||||
checked={String(p.value) === opt.value}
|
||||
class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 checked:border-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800"
|
||||
class="wr:shrink-0 wr:mt-0.5 wr:border-gray-200 wr:rounded-full wr:text-blue-600 wr:focus:ring-blue-500 wr:checked:border-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-800 wr:dark:border-neutral-700 wr:dark:checked:bg-blue-500 wr:dark:checked:border-blue-500 wr:dark:focus:ring-offset-gray-800"
|
||||
disabled={opt.disabled || p.disabled}
|
||||
data-control
|
||||
/>
|
||||
<span class="text-sm text-foreground">
|
||||
<span class="wr:text-sm wr:text-foreground">
|
||||
{opt.label}
|
||||
</span>
|
||||
</label>
|
||||
@@ -397,24 +411,24 @@ const controlWrap = "relative";
|
||||
|
||||
{
|
||||
p.kind === "switch" && (
|
||||
<div class="flex items-center gap-3">
|
||||
<label class="relative inline-block w-11 h-6 cursor-pointer">
|
||||
<div class="wr:flex wr:items-center wr:gap-3">
|
||||
<label class="wr:relative wr:inline-block wr:w-11 wr:h-6 wr:cursor-pointer">
|
||||
<input
|
||||
id={fieldId}
|
||||
name={p.name}
|
||||
type="checkbox"
|
||||
class="sr-only peer"
|
||||
class="wr:sr-only wr:peer"
|
||||
checked={!!p.value}
|
||||
disabled={p.disabled}
|
||||
data-control
|
||||
/>
|
||||
<span class="absolute inset-0 bg-gray-200 rounded-full transition-colors duration-200 ease-in-out peer-checked:bg-blue-600 dark:bg-neutral-700 dark:peer-checked:bg-blue-500 peer-disabled:opacity-50 peer-disabled:pointer-events-none" />
|
||||
<span class="absolute top-1/2 start-0.5 -translate-y-1/2 size-5 bg-white rounded-full shadow-xs transition-transform duration-200 ease-in-out peer-checked:translate-x-full dark:bg-neutral-400 dark:peer-checked:bg-white" />
|
||||
<span class="wr:absolute wr:inset-0 wr:bg-gray-200 wr:rounded-full wr:transition-colors wr:duration-200 wr:ease-in-out wr:peer-checked:bg-blue-600 wr:dark:bg-neutral-700 wr:dark:peer-checked:bg-blue-500 wr:peer-disabled:opacity-50 wr:peer-disabled:pointer-events-none" />
|
||||
<span class="wr:absolute wr:top-1/2 wr:start-0.5 wr:-translate-y-1/2 wr:size-5 wr:bg-white wr:rounded-full wr:shadow-xs wr:transition-transform wr:duration-200 wr:ease-in-out wr:peer-checked:translate-x-full wr:dark:bg-neutral-400 wr:dark:peer-checked:bg-white" />
|
||||
</label>
|
||||
{p.label && (
|
||||
<label
|
||||
for={fieldId}
|
||||
class="text-sm text-gray-500 dark:text-neutral-400"
|
||||
class="wr:text-sm wr:text-gray-500 wr:dark:text-neutral-400"
|
||||
>
|
||||
{p.label}
|
||||
</label>
|
||||
@@ -431,6 +445,5 @@ const controlWrap = "relative";
|
||||
)
|
||||
}
|
||||
|
||||
<!-- Always-present error container (client fills it) -->
|
||||
<p id={errId} class={errCls} hidden>{p.error ?? ""}</p>
|
||||
</div>
|
||||
|
||||
+20
-11
@@ -34,20 +34,22 @@ const {
|
||||
}: Props = Astro.props;
|
||||
|
||||
const gridCls =
|
||||
columns === 2 ? "grid grid-cols-1 sm:grid-cols-2 gap-4" : "space-y-4";
|
||||
columns === 2
|
||||
? "wr:grid wr:grid-cols-1 wr:sm:grid-cols-2 wr:gap-4"
|
||||
: "wr:space-y-4";
|
||||
const actionsJustify =
|
||||
actionsAlign === "start"
|
||||
? "justify-start"
|
||||
? "wr:justify-start"
|
||||
: actionsAlign === "center"
|
||||
? "justify-center"
|
||||
: "justify-end";
|
||||
? "wr:justify-center"
|
||||
: "wr:justify-end";
|
||||
|
||||
const formId = `f-${Math.random().toString(36).slice(2)}`;
|
||||
---
|
||||
|
||||
<form
|
||||
id={formId}
|
||||
class={cn("space-y-4", className)}
|
||||
class={cn("wr:space-y-4", className)}
|
||||
{...rest}
|
||||
data-schema={schemaName ?? ""}
|
||||
data-onsubmit={onSubmit ?? ""}
|
||||
@@ -58,12 +60,14 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
||||
<div>
|
||||
{
|
||||
title && (
|
||||
<h2 class="text-lg font-semibold text-foreground">{title}</h2>
|
||||
<h2 class="wr:text-lg wr:font-semibold wr:text-foreground">
|
||||
{title}
|
||||
</h2>
|
||||
)
|
||||
}
|
||||
{
|
||||
description && (
|
||||
<p class="text-sm text-muted-foreground mt-1 text-gray-600 dark:text-neutral-400">
|
||||
<p class="wr:text-sm wr:text-muted-foreground wr:mt-1 wr:text-gray-600 wr:dark:text-neutral-400">
|
||||
{description}
|
||||
</p>
|
||||
)
|
||||
@@ -74,7 +78,7 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<div class={cn("flex gap-3", actionsJustify)}>
|
||||
<div class={cn("wr:flex wr:gap-3", actionsJustify)}>
|
||||
<Button type="submit" variant="solid" color="primary" icon={submitIcon}>
|
||||
{submitLabel}
|
||||
</Button>
|
||||
@@ -82,11 +86,16 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Client validation & submit hook (no zod import here) -->
|
||||
<script type="module" is:inline define:vars={{ formId, showSuccesInput }}>
|
||||
const start = () => {
|
||||
const INVALID_KLS = ["!border-danger", "focus-visible:ring-danger/40"];
|
||||
const VALID_KLS = ["!border-success", "focus-visible:ring-success/40"];
|
||||
const INVALID_KLS = [
|
||||
"wr:!border-danger",
|
||||
"wr:focus-visible:ring-danger/40",
|
||||
];
|
||||
const VALID_KLS = [
|
||||
"wr:!border-success",
|
||||
"wr:focus-visible:ring-success/40",
|
||||
];
|
||||
|
||||
const form = document.getElementById(formId);
|
||||
if (!form || form.dataset.__afInit) return;
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
import type { HTMLAttributes } from "astro/types";
|
||||
|
||||
import { cn } from "../utils/cn";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { getDynamicIcon } from "../utils/icon";
|
||||
|
||||
const iconClass = cva("text-current", {
|
||||
variants: {
|
||||
size: {
|
||||
sm: "size-4",
|
||||
md: "size-6",
|
||||
lg: "size-8",
|
||||
xl: "size-14",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
},
|
||||
});
|
||||
|
||||
interface Props extends HTMLAttributes<"svg">, VariantProps<typeof iconClass> {
|
||||
size?: "sm" | "md" | "lg" | "xl";
|
||||
name: string;
|
||||
}
|
||||
|
||||
const { size = "md", name, class: className, ...rest }: Props = Astro.props;
|
||||
|
||||
const svg = await getDynamicIcon(name);
|
||||
---
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
class={cn(iconClass({ size, className }))}
|
||||
{...rest}
|
||||
>
|
||||
<Fragment set:html={svg} />
|
||||
</svg>
|
||||
@@ -43,36 +43,36 @@ const summarySSR = selected.size
|
||||
|
||||
const sizeCls =
|
||||
p.size === "sm"
|
||||
? "h-9 px-3 text-sm"
|
||||
? "wr:h-9 wr:px-3 wr:text-sm"
|
||||
: p.size === "lg"
|
||||
? "h-11 px-4 text-base"
|
||||
: "h-10 px-3 text-sm";
|
||||
? "wr:h-11 wr:px-4 wr:text-base"
|
||||
: "wr:h-10 wr:px-3 wr:text-sm";
|
||||
|
||||
const controlCls =
|
||||
"py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg sm:text-sm " +
|
||||
"focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none " +
|
||||
"dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600";
|
||||
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm " +
|
||||
"wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none " +
|
||||
"wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600";
|
||||
|
||||
const chipBase =
|
||||
"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs bg-muted text-foreground";
|
||||
"wr:inline-flex wr:items-center wr:gap-1 wr:rounded-full wr:px-2 wr:py-0.5 wr:text-xs wr:bg-muted wr:text-foreground";
|
||||
|
||||
const containerId = `ms-${Math.random().toString(36).slice(2)}`;
|
||||
const displayMode = p.display ?? "text";
|
||||
---
|
||||
|
||||
<div class={cn("space-y-1.5", p.class)} data-field={p.name} id={containerId}>
|
||||
<div class={cn("wr:space-y-1.5", p.class)} data-field={p.name} id={containerId}>
|
||||
{
|
||||
p.label && (
|
||||
<label
|
||||
for={fieldId}
|
||||
class="mb-1.5 block text-sm font-medium text-foreground"
|
||||
class="wr:mb-1.5 wr:block wr:text-sm wr:font-medium wr:text-foreground"
|
||||
>
|
||||
{p.label} {p.required && <span class="text-danger">*</span>}
|
||||
{p.label} {p.required && <span class="wr:text-danger">*</span>}
|
||||
</label>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="relative">
|
||||
<div class="wr:relative">
|
||||
<input
|
||||
id={fieldId}
|
||||
type="text"
|
||||
@@ -85,8 +85,8 @@ const displayMode = p.display ?? "text";
|
||||
class={cn(
|
||||
controlCls,
|
||||
sizeCls,
|
||||
"pr-10 cursor-pointer",
|
||||
displayMode === "chips" && "pl-3",
|
||||
"wr:pr-10 wr:cursor-pointer",
|
||||
displayMode === "chips" && "wr:pl-3",
|
||||
)}
|
||||
placeholder={p.placeholder ?? "Select..."}
|
||||
value={displayMode === "text" ? summarySSR : ""}
|
||||
@@ -95,58 +95,60 @@ const displayMode = p.display ?? "text";
|
||||
{...p.disabled ? { disabled: true } : {}}
|
||||
/>
|
||||
|
||||
<div class="absolute inset-y-0 right-0 flex items-center gap-1 pr-2">
|
||||
<div
|
||||
class="wr:absolute wr:inset-y-0 wr:right-0 wr:flex wr:items-center wr:gap-1 wr:pr-2"
|
||||
>
|
||||
{
|
||||
p.clearable !== false && !p.disabled && (
|
||||
<button
|
||||
type="button"
|
||||
class={cn(
|
||||
"p-1 rounded hover:bg-muted",
|
||||
selected.size === 0 && "hidden",
|
||||
"wr:p-1 wr:rounded wr:hover:bg-muted",
|
||||
selected.size === 0 && "wr:hidden",
|
||||
)}
|
||||
data-ms-clear
|
||||
aria-label="Clear selection"
|
||||
>
|
||||
<Icon name="mdi:close" class="size-4" />
|
||||
<Icon name="mdi:close" class="wr:size-4" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
<button
|
||||
type="button"
|
||||
class="p-1 rounded hover:bg-muted"
|
||||
class="wr:p-1 wr:rounded wr:hover:bg-muted"
|
||||
data-ms-toggle
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
<Icon name="mdi:chevron-down" class="size-5" />
|
||||
<Icon name="mdi:chevron-down" class="wr:size-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-ms-chips
|
||||
class={cn(
|
||||
"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 flex flex-wrap gap-1 pr-14",
|
||||
displayMode === "chips" ? "" : "hidden",
|
||||
"wr:pointer-events-none wr:absolute wr:left-3 wr:top-1/2 wr:-translate-y-1/2 wr:flex wr:flex-wrap wr:gap-1 wr:pr-14",
|
||||
displayMode === "chips" ? "" : "wr:hidden",
|
||||
)}
|
||||
>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="absolute border-border bg-popover text-popover-foreground shadow-lg hidden mt-2 z-50 w-full max-h-72 p-1 space-y-0.5 bg-white border border-gray-200 rounded-lg overflow-hidden overflow-y-auto [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-track]:bg-gray-100 [&::-webkit-scrollbar-thumb]:bg-gray-300 dark:[&::-webkit-scrollbar-track]:bg-neutral-700 dark:[&::-webkit-scrollbar-thumb]:bg-neutral-500 dark:bg-neutral-900 dark:border-neutral-700"
|
||||
class="wr:absolute wr:border-border wr:bg-popover wr:text-popover-foreground wr:shadow-lg wr:hidden wr:mt-2 wr:z-50 wr:w-full wr:max-h-72 wr:p-1 wr:space-y-0.5 wr:bg-white wr:border wr:border-gray-200 wr:rounded-lg wr:overflow-hidden wr:overflow-y-auto wr:[&::-webkit-scrollbar]:w-2 wr:[&::-webkit-scrollbar-thumb]:rounded-full wr:[&::-webkit-scrollbar-track]:bg-gray-100 wr:[&::-webkit-scrollbar-thumb]:bg-gray-300 wr:dark:[&::-webkit-scrollbar-track]:bg-neutral-700 wr:dark:[&::-webkit-scrollbar-thumb]:bg-neutral-500 wr:dark:bg-neutral-900 wr:dark:border-neutral-700"
|
||||
id={`${containerId}-panel`}
|
||||
>
|
||||
{
|
||||
p.searchable !== false && (
|
||||
<div class="p-2 border-b border-border">
|
||||
<div class="relative">
|
||||
<div class="wr:p-2 wr:border-b wr:border-border">
|
||||
<div class="wr:relative">
|
||||
<Icon
|
||||
name="mdi:magnify"
|
||||
class="absolute left-2 top-1/2 -translate-y-1/2 size-4 text-muted-foreground"
|
||||
class="wr:absolute wr:left-2 wr:top-1/2 wr:-translate-y-1/2 wr:size-4 wr:text-muted-foreground"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class={cn(
|
||||
"py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg sm:text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600",
|
||||
"h-9 pl-8 pr-2 text-sm",
|
||||
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-gray-200 wr:rounded-lg wr:sm:text-sm wr:focus:border-blue-500 wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-neutral-900 wr:dark:border-neutral-700 wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
|
||||
"wr:h-9 wr:pl-8 wr:pr-2 wr:text-sm",
|
||||
)}
|
||||
placeholder="Search…"
|
||||
data-ms-search
|
||||
@@ -161,15 +163,16 @@ const displayMode = p.display ?? "text";
|
||||
role="listbox"
|
||||
aria-multiselectable="true"
|
||||
id={`${containerId}-listbox`}
|
||||
class="max-h-56 overflow-auto p-1"
|
||||
class="wr:max-h-56 wr:overflow-auto wr:p-1"
|
||||
data-ms-list
|
||||
>
|
||||
{
|
||||
p.options.map((opt) => (
|
||||
<li
|
||||
class={cn(
|
||||
"flex items-center gap-2 px-2 py-2 rounded hover:bg-muted",
|
||||
opt.disabled && "opacity-60 cursor-not-allowed",
|
||||
"wr:flex wr:items-center wr:gap-2 wr:px-2 wr:py-2 wr:rounded wr:hover:bg-muted",
|
||||
opt.disabled &&
|
||||
"wr:opacity-60 wr:cursor-not-allowed",
|
||||
)}
|
||||
data-ms-item
|
||||
data-label={opt.label.toLowerCase()}
|
||||
@@ -180,36 +183,36 @@ const displayMode = p.display ?? "text";
|
||||
value={opt.value}
|
||||
checked={selected.has(opt.value)}
|
||||
disabled={p.disabled || opt.disabled}
|
||||
class="size-4 rounded border-border text-primary accent-primary focus:ring-primary/40"
|
||||
class="wr:size-4 wr:rounded wr:border-border wr:text-primary wr:accent-primary wr:focus:ring-primary/40"
|
||||
data-control
|
||||
/>
|
||||
<span class="text-sm">{opt.label}</span>
|
||||
<span class="wr:text-sm">{opt.label}</span>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between gap-2 p-2 border-t border-border"
|
||||
class="wr:flex wr:items-center wr:justify-between wr:gap-2 wr:p-2 wr:border-t wr:border-border"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="text-sm text-primary hover:underline disabled:opacity-50"
|
||||
class="wr:text-sm wr:text-primary wr:hover:underline wr:disabled:opacity-50"
|
||||
data-ms-select-all
|
||||
>
|
||||
Select all
|
||||
</button>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="wr:flex wr:items-center wr:gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="text-sm text-muted-foreground hover:underline"
|
||||
class="wr:text-sm wr:text-muted-foreground wr:hover:underline"
|
||||
data-ms-cancel
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="text-sm text-primary hover:underline"
|
||||
class="wr:text-sm wr:text-primary wr:hover:underline"
|
||||
data-ms-apply
|
||||
>
|
||||
Apply
|
||||
@@ -223,13 +226,15 @@ const displayMode = p.display ?? "text";
|
||||
p.description && (
|
||||
<p
|
||||
id={descId}
|
||||
class="mt-2 text-sm text-gray-500 dark:text-neutral-500"
|
||||
class="wr:mt-2 wr:text-sm wr:text-gray-500 wr:dark:text-neutral-500"
|
||||
>
|
||||
{p.description}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
<p id={errId} class="mt-1 text-xs text-danger" hidden>{p.error ?? ""}</p>
|
||||
<p id={errId} class="wr:mt-1 wr:text-xs wr:text-danger" hidden>
|
||||
{p.error ?? ""}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script
|
||||
@@ -265,21 +270,21 @@ const displayMode = p.display ?? "text";
|
||||
function setExpanded(v, { focusSearch = false } = {}) {
|
||||
open = v;
|
||||
input.setAttribute("aria-expanded", String(open));
|
||||
panel.classList.toggle("hidden", !open);
|
||||
panel.classList.toggle("wr:hidden", !open);
|
||||
if (open && focusSearch) sch?.focus();
|
||||
}
|
||||
|
||||
function makeChip(label) {
|
||||
const span = document.createElement("span");
|
||||
span.className =
|
||||
"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs bg-muted text-foreground";
|
||||
"wr:inline-flex wr:items-center wr:gap-1 wr:rounded-full wr:px-2 wr:py-0.5 wr:text-xs wr:bg-muted wr:text-foreground";
|
||||
span.textContent = label;
|
||||
return span;
|
||||
}
|
||||
|
||||
function toggleClear(show) {
|
||||
if (!btnClr) return;
|
||||
btnClr.classList.toggle("hidden", !show);
|
||||
btnClr.classList.toggle("wr:hidden", !show);
|
||||
}
|
||||
|
||||
function updateSummary() {
|
||||
@@ -301,7 +306,7 @@ const displayMode = p.display ?? "text";
|
||||
input.placeholder = labels.length ? "" : origPlaceholder;
|
||||
if (chips) {
|
||||
chips.innerHTML = "";
|
||||
chips.classList.add("hidden");
|
||||
chips.classList.add("wr:hidden");
|
||||
}
|
||||
} else {
|
||||
input.value = "";
|
||||
@@ -314,7 +319,7 @@ const displayMode = p.display ?? "text";
|
||||
.forEach((lab) => chips.appendChild(makeChip(lab)));
|
||||
const extra = labels.length - max;
|
||||
if (extra > 0) chips.appendChild(makeChip(`+${extra}`));
|
||||
chips.classList.toggle("hidden", labels.length === 0);
|
||||
chips.classList.toggle("wr:hidden", labels.length === 0);
|
||||
}
|
||||
|
||||
toggleClear(labels.length > 0);
|
||||
@@ -376,7 +381,7 @@ const displayMode = p.display ?? "text";
|
||||
const q = sch.value.trim().toLowerCase();
|
||||
root.querySelectorAll("[data-ms-item]").forEach((li) => {
|
||||
const m = (li.getAttribute("data-label") || "").includes(q);
|
||||
li.classList.toggle("hidden", !m);
|
||||
li.classList.toggle("wr:hidden", !m);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user