feat(app): v2 wsl ui (#34233)
Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>
This commit is contained in:
parent
bf18cc971f
commit
4d91f0cf28
20 changed files with 1612 additions and 618 deletions
|
|
@ -28,7 +28,7 @@
|
|||
outline: none;
|
||||
}
|
||||
|
||||
[data-component="button-v2"]:is(:focus-visible, [data-state="focus"]):not(:disabled) {
|
||||
[data-component="button-v2"]:is(:focus-visible, [data-state="focus"]):not(:disabled):not([data-variant="loading"]) {
|
||||
outline: 2px solid var(--v2-border-border-focus);
|
||||
outline-offset: 2.5px;
|
||||
}
|
||||
|
|
@ -170,6 +170,15 @@
|
|||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Loading */
|
||||
[data-component="button-v2"][data-variant="loading"] {
|
||||
background: #f2f2f2;
|
||||
color: var(--v2-text-text-base);
|
||||
box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.08);
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Ghost */
|
||||
[data-component="button-v2"][data-variant="ghost"] {
|
||||
background-color: transparent;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { ButtonV2 } from "./button-v2"
|
||||
|
||||
const docs = `### Overview
|
||||
Button v2 with three visual variants and two sizes.
|
||||
Button v2 with visual variants and three sizes.
|
||||
|
||||
### API
|
||||
- \`variant\`: "neutral" | "danger" | "contrast" | "ghost" | "ghost-muted".
|
||||
- \`size\`: "normal" | "large".
|
||||
- \`variant\`: "neutral" | "danger" | "contrast" | "ghost" | "ghost-muted" | "loading".
|
||||
- \`size\`: "small" | "normal" | "large".
|
||||
- \`icon\`: Optional icon name.
|
||||
- Inherits Kobalte Button props and native button attributes.
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ export default {
|
|||
},
|
||||
variant: {
|
||||
control: "select",
|
||||
options: ["neutral", "danger", "contrast", "ghost", "ghost-muted"],
|
||||
options: ["neutral", "danger", "contrast", "ghost", "ghost-muted", "loading"],
|
||||
},
|
||||
size: {
|
||||
control: "select",
|
||||
|
|
@ -67,6 +67,7 @@ export const Variants = {
|
|||
<ButtonV2 variant="ghost-muted" icon="edit">
|
||||
Ghost muted
|
||||
</ButtonV2>
|
||||
<ButtonV2 variant="loading">Loading</ButtonV2>
|
||||
</div>
|
||||
),
|
||||
}
|
||||
|
|
@ -116,7 +117,7 @@ export const Icon = {
|
|||
|
||||
export const AllStates = {
|
||||
render: () => {
|
||||
const variants = ["neutral", "danger", "contrast", "ghost", "ghost-muted"] as const
|
||||
const variants = ["neutral", "danger", "contrast", "ghost", "ghost-muted", "loading"] as const
|
||||
const states = ["default", "hover", "pressed", "focus", "disabled"] as const
|
||||
const toTitleCase = (value: string) => value.charAt(0).toUpperCase() + value.slice(1)
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export interface ButtonV2Props
|
|||
extends ComponentProps<typeof Kobalte>,
|
||||
Pick<ComponentProps<"button">, "class" | "classList" | "children"> {
|
||||
size?: "small" | "normal" | "large"
|
||||
variant?: "neutral" | "danger" | "contrast" | "ghost" | "ghost-muted" | "outline"
|
||||
variant?: "neutral" | "danger" | "outline" | "contrast" | "ghost" | "ghost-muted" | "loading"
|
||||
icon?: IconProps["name"]
|
||||
}
|
||||
|
||||
|
|
|
|||
32
packages/ui/src/v2/components/loader-v2.css
Normal file
32
packages/ui/src/v2/components/loader-v2.css
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
[data-component="loader-v2"] {
|
||||
--_duration: 900ms;
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
color: var(--v2-icon-icon-muted, #808080);
|
||||
animation: loader-v2-spin var(--_duration) linear infinite;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
[data-component="loader-v2"] [data-slot="loader-v2-background"] {
|
||||
stroke: currentColor;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
[data-component="loader-v2"] [data-slot="loader-v2-progress"] {
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
transform: rotate(-90deg);
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
@keyframes loader-v2-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
[data-component="loader-v2"] {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
42
packages/ui/src/v2/components/loader-v2.stories.tsx
Normal file
42
packages/ui/src/v2/components/loader-v2.stories.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { LoaderV2 } from "./loader-v2"
|
||||
|
||||
const docs = `### Overview
|
||||
Circular v2 loader for compact loading states.
|
||||
|
||||
### API
|
||||
- Accepts standard SVG props.
|
||||
|
||||
### Behavior
|
||||
- The foreground ring covers 33% of the circumference and rotates continuously.
|
||||
|
||||
### Accessibility
|
||||
- Sets \`aria-hidden="true"\` by default.
|
||||
`
|
||||
|
||||
export default {
|
||||
title: "UI V2/Loader",
|
||||
id: "components-loader-v2",
|
||||
component: LoaderV2,
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: docs,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const Basic = {
|
||||
render: () => <LoaderV2 />,
|
||||
}
|
||||
|
||||
export const Sizes = {
|
||||
render: () => (
|
||||
<div style={{ display: "flex", gap: "16px", "align-items": "center" }}>
|
||||
<LoaderV2 width={12} height={12} />
|
||||
<LoaderV2 />
|
||||
<LoaderV2 width={24} height={24} />
|
||||
</div>
|
||||
),
|
||||
}
|
||||
31
packages/ui/src/v2/components/loader-v2.tsx
Normal file
31
packages/ui/src/v2/components/loader-v2.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { splitProps, type ComponentProps } from "solid-js"
|
||||
import "./loader-v2.css"
|
||||
|
||||
export function LoaderV2(props: ComponentProps<"svg">) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "width", "height"])
|
||||
return (
|
||||
<svg
|
||||
{...rest}
|
||||
class={local.class}
|
||||
classList={local.classList}
|
||||
width={local.width ?? 16}
|
||||
height={local.height ?? 16}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
data-component="loader-v2"
|
||||
aria-hidden={rest["aria-hidden"] ?? "true"}
|
||||
>
|
||||
<circle cx="8" cy="8" r="6" data-slot="loader-v2-background" stroke-width="2" />
|
||||
<circle
|
||||
cx="8"
|
||||
cy="8"
|
||||
r="6"
|
||||
data-slot="loader-v2-progress"
|
||||
pathLength="100"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="33 67"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
}
|
||||
|
||||
[data-slot="radio-v2-item"] {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
|
|
@ -131,10 +132,6 @@
|
|||
linear-gradient(180deg, var(--v2-alpha-light-20) 0%, var(--v2-alpha-light-0) 100%), var(--v2-background-bg-accent);
|
||||
}
|
||||
|
||||
&:where([data-checked][data-disabled]) [data-slot="radio-v2-item-control"] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:where([data-invalid]):where(:not([data-checked])) [data-slot="radio-v2-item-control"] {
|
||||
background: var(--v2-state-bg-danger);
|
||||
box-shadow: inset 0 0 0 0.5px var(--v2-state-border-danger);
|
||||
|
|
@ -195,8 +192,11 @@
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
&:where([data-disabled]) [data-slot="radio-v2-item-label"],
|
||||
&:where([data-disabled]) [data-slot="radio-v2-item-label-text"] {
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
&:where([data-disabled]) [data-slot="radio-v2-item-description"] {
|
||||
opacity: 0.5;
|
||||
color: var(--v2-text-text-faint);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue