diff options
Diffstat (limited to 'packages/ui/src/components/text-field.tsx')
| -rw-r--r-- | packages/ui/src/components/text-field.tsx | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/packages/ui/src/components/text-field.tsx b/packages/ui/src/components/text-field.tsx new file mode 100644 index 000000000..63ffb2594 --- /dev/null +++ b/packages/ui/src/components/text-field.tsx @@ -0,0 +1,103 @@ +import { TextField as Kobalte } from "@kobalte/core/text-field" +import { createSignal, Show, splitProps } from "solid-js" +import type { ComponentProps } from "solid-js" +import { IconButton } from "./icon-button" +import { Tooltip } from "./tooltip" + +export interface TextFieldProps + extends ComponentProps<typeof Kobalte.Input>, + Partial< + Pick< + ComponentProps<typeof Kobalte>, + | "name" + | "defaultValue" + | "value" + | "onChange" + | "onKeyDown" + | "validationState" + | "required" + | "disabled" + | "readOnly" + > + > { + label?: string + hideLabel?: boolean + description?: string + error?: string + variant?: "normal" | "ghost" + copyable?: boolean +} + +export function TextField(props: TextFieldProps) { + const [local, others] = splitProps(props, [ + "name", + "defaultValue", + "value", + "onChange", + "onKeyDown", + "validationState", + "required", + "disabled", + "readOnly", + "class", + "label", + "hideLabel", + "description", + "error", + "variant", + "copyable", + ]) + const [copied, setCopied] = createSignal(false) + + async function handleCopy() { + const value = local.value ?? local.defaultValue ?? "" + await navigator.clipboard.writeText(value) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } + + return ( + <Kobalte + data-component="input" + data-variant={local.variant || "normal"} + name={local.name} + defaultValue={local.defaultValue} + value={local.value} + onChange={local.onChange} + onKeyDown={local.onKeyDown} + required={local.required} + disabled={local.disabled} + readOnly={local.readOnly} + validationState={local.validationState} + > + <Show when={local.label}> + <Kobalte.Label data-slot="input-label" classList={{ "sr-only": local.hideLabel }}> + {local.label} + </Kobalte.Label> + </Show> + <div data-slot="input-wrapper"> + <Kobalte.Input {...others} data-slot="input-input" class={local.class} /> + <Show when={local.copyable}> + <Tooltip value={copied() ? "Copied" : "Copy to clipboard"} placement="top" gutter={8}> + <IconButton + type="button" + icon={copied() ? "check" : "copy"} + variant="ghost" + onClick={handleCopy} + data-slot="input-copy-button" + /> + </Tooltip> + </Show> + </div> + <Show when={local.description}> + <Kobalte.Description data-slot="input-description">{local.description}</Kobalte.Description> + </Show> + <Kobalte.ErrorMessage data-slot="input-error">{local.error}</Kobalte.ErrorMessage> + </Kobalte> + ) +} + +/** @deprecated Use TextField instead */ +export const Input = TextField +/** @deprecated Use TextFieldProps instead */ +export type InputProps = TextFieldProps |
