From 3bb546c94d6bb295bfeafdafbb9d34b7cc462560 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:16:50 -0600 Subject: wip(desktop): progress --- packages/ui/src/components/button.css | 32 ++++++------ packages/ui/src/components/dialog.tsx | 7 ++- packages/ui/src/components/icon.tsx | 1 + packages/ui/src/components/input.css | 76 +++++++++++++++++++++++++++- packages/ui/src/components/input.tsx | 42 ++++++++++++--- packages/ui/src/components/select-dialog.tsx | 7 +-- packages/ui/src/hooks/use-filtered-list.tsx | 7 +-- 7 files changed, 143 insertions(+), 29 deletions(-) (limited to 'packages/ui/src') diff --git a/packages/ui/src/components/button.css b/packages/ui/src/components/button.css index f95317028..3a32672fe 100644 --- a/packages/ui/src/components/button.css +++ b/packages/ui/src/components/button.css @@ -11,27 +11,29 @@ outline: none; &[data-variant="primary"] { - border-color: var(--border-base); - background-color: var(--surface-brand-base); - color: var(--text-on-brand-strong); + background-color: var(--icon-strong-base); + border-color: var(--border-weak-base); + color: var(--icon-invert-base); + + [data-slot="icon-svg"] { + color: var(--icon-invert-base); + } &:hover:not(:disabled) { - border-color: var(--border-hover); - background-color: var(--surface-brand-hover); + background-color: var(--icon-strong-hover); } &:focus:not(:disabled) { - border-color: var(--border-focus); - background-color: var(--surface-brand-focus); + background-color: var(--icon-strong-focus); } &:active:not(:disabled) { - border-color: var(--border-active); - background-color: var(--surface-brand-active); + background-color: var(--icon-strong-active); } &:disabled { - border-color: var(--border-disabled); - background-color: var(--surface-disabled); - color: var(--text-weak); - cursor: not-allowed; + background-color: var(--icon-strong-disabled); + + [data-slot="icon-svg"] { + color: var(--icon-invert-base); + } } } @@ -120,13 +122,13 @@ &[data-size="large"] { height: 32px; - padding: 0 8px; + padding: 6px 12px; &[data-icon] { padding: 0 12px 0 8px; } - gap: 8px; + gap: 4px; /* text-14-medium */ font-family: var(--font-family-sans); diff --git a/packages/ui/src/components/dialog.tsx b/packages/ui/src/components/dialog.tsx index a16705a57..56053278d 100644 --- a/packages/ui/src/components/dialog.tsx +++ b/packages/ui/src/components/dialog.tsx @@ -5,7 +5,7 @@ import { DialogCloseButtonProps, DialogDescriptionProps, } from "@kobalte/core/dialog" -import { ComponentProps, type JSX, onCleanup, Show, splitProps } from "solid-js" +import { ComponentProps, type JSX, onCleanup, onMount, Show, splitProps } from "solid-js" import { IconButton } from "./icon-button" export interface DialogProps extends DialogRootProps { @@ -35,6 +35,11 @@ export function DialogRoot(props: DialogProps) { }) } + onMount(() => { + // @ts-ignore + document?.activeElement?.blur?.() + }) + return ( diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 97f2e8eab..080a6274d 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -3,6 +3,7 @@ import { splitProps, type ComponentProps } from "solid-js" const icons = { "align-right": ``, "arrow-up": ``, + "arrow-left": ``, "bubble-5": ``, "bullet-list": ``, "check-small": ``, diff --git a/packages/ui/src/components/input.css b/packages/ui/src/components/input.css index c5f8cb8c5..276e8069b 100644 --- a/packages/ui/src/components/input.css +++ b/packages/ui/src/components/input.css @@ -1,6 +1,5 @@ [data-component="input"] { width: 100%; - /* [data-slot="input-label"] {} */ [data-slot="input-input"] { width: 100%; @@ -22,4 +21,79 @@ color: var(--text-weak); } } + + &[data-variant="normal"] { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + + [data-slot="input-label"] { + color: var(--text-weak); + + /* text-12-medium */ + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-style: normal; + font-weight: var(--font-weight-medium); + line-height: 18px; /* 150% */ + letter-spacing: var(--letter-spacing-normal); + } + + [data-slot="input-input"] { + color: var(--text-strong); + + display: flex; + height: 32px; + padding: 2px 12px; + align-items: center; + gap: 8px; + align-self: stretch; + + border-radius: var(--radius-md); + border: 1px solid var(--border-weak-base); + background: var(--input-base); + + /* text-14-regular */ + font-family: var(--font-family-sans); + font-size: 14px; + font-style: normal; + font-weight: var(--font-weight-regular); + line-height: var(--line-height-large); /* 142.857% */ + letter-spacing: var(--letter-spacing-normal); + + &:focus { + outline: none; + + /* border/shadow-xs/select */ + box-shadow: + 0 0 0 3px var(--border-weak-selected), + 0 0 0 1px var(--border-selected), + 0 1px 2px -1px rgba(19, 16, 16, 0.25), + 0 1px 2px 0 rgba(19, 16, 16, 0.08), + 0 1px 3px 0 rgba(19, 16, 16, 0.12); + } + + &[data-invalid] { + background: var(--surface-critical-weak); + border: 1px solid var(--border-critical-selected); + } + + &::placeholder { + color: var(--text-weak); + } + } + + [data-slot="input-error"] { + color: var(--text-on-critical-base); + + /* text-12-medium */ + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-style: normal; + font-weight: var(--font-weight-medium); + line-height: 18px; /* 150% */ + letter-spacing: var(--letter-spacing-normal); + } + } } diff --git a/packages/ui/src/components/input.tsx b/packages/ui/src/components/input.tsx index 82f704e8c..8e2a115c6 100644 --- a/packages/ui/src/components/input.tsx +++ b/packages/ui/src/components/input.tsx @@ -4,31 +4,61 @@ import type { ComponentProps } from "solid-js" export interface InputProps extends ComponentProps, - Partial, "value" | "onChange" | "onKeyDown">> { + Partial< + Pick< + ComponentProps, + | "name" + | "defaultValue" + | "value" + | "onChange" + | "onKeyDown" + | "validationState" + | "required" + | "disabled" + | "readOnly" + > + > { label?: string hideLabel?: boolean hidden?: boolean description?: string + error?: string + variant?: "normal" | "ghost" } export function Input(props: InputProps) { const [local, others] = splitProps(props, [ + "name", + "defaultValue", + "value", + "onChange", + "onKeyDown", + "validationState", + "required", + "disabled", + "readOnly", "class", "label", "hidden", "hideLabel", "description", - "value", - "onChange", - "onKeyDown", + "error", + "variant", ]) return ( @@ -39,7 +69,7 @@ export function Input(props: InputProps) { {local.description} - + {local.error} ) } diff --git a/packages/ui/src/components/select-dialog.tsx b/packages/ui/src/components/select-dialog.tsx index 952ba881f..efa6c405b 100644 --- a/packages/ui/src/components/select-dialog.tsx +++ b/packages/ui/src/components/select-dialog.tsx @@ -1,9 +1,9 @@ import { createEffect, Show, type JSX, splitProps, createSignal } from "solid-js" import { Dialog, DialogProps } from "./dialog" import { Icon } from "./icon" -import { Input } from "./input" import { IconButton } from "./icon-button" import { List, ListRef, ListProps } from "./list" +import { Input } from "./input" interface SelectDialogProps extends Omit, "filter">, @@ -29,8 +29,8 @@ export function SelectDialog(props: SelectDialogProps) { }) }) - const handleSelect = (item: T | undefined) => { - others.onSelect?.(item) + const handleSelect = (item: T | undefined, index: number) => { + others.onSelect?.(item, index) closeButton.click() } @@ -58,6 +58,7 @@ export function SelectDialog(props: SelectDialogProps) { { groupBy?: (x: T) => string sortBy?: (a: T, b: T) => number sortGroupsBy?: (a: { category: string; items: T[] }, b: { category: string; items: T[] }) => number - onSelect?: (value: T | undefined) => void + onSelect?: (value: T | undefined, index: number) => void } export function useFilteredList(props: FilteredListProps) { @@ -63,8 +63,9 @@ export function useFilteredList(props: FilteredListProps) { const onKeyDown = (event: KeyboardEvent) => { if (event.key === "Enter") { event.preventDefault() - const selected = flat().find((x) => props.key(x) === list.active()) - if (selected) props.onSelect?.(selected) + const selectedIndex = flat().findIndex((x) => props.key(x) === list.active()) + const selected = flat()[selectedIndex] + if (selected) props.onSelect?.(selected, selectedIndex) } else { list.onKeyDown(event) } -- cgit v1.2.3