| import { type ComponentProps, type JSX, Show, splitProps } from "solid-js" |
| import { Icon } from "./icon" |
| import { useI18n } from "../../context/i18n" |
| import "./inline-input-v2.css" |
|
|
| export interface InlineInputV2Props extends Omit<ComponentProps<"input">, "type" | "prefix"> { |
| |
| prefix: JSX.Element |
| |
| labelWidth?: number | string |
| |
| showCopyButton?: boolean |
| |
| copyLabel?: string |
| onCopyClick?: (event: MouseEvent) => void |
| |
| numeric?: boolean |
| |
| invalid?: boolean |
| |
| appearance?: "base" | "large" |
| type?: ComponentProps<"input">["type"] |
| } |
|
|
| export function InlineInputV2(props: InlineInputV2Props) { |
| const i18n = useI18n() |
| const [local, inputProps] = splitProps(props, [ |
| "class", |
| "classList", |
| "prefix", |
| "labelWidth", |
| "showCopyButton", |
| "copyLabel", |
| "onCopyClick", |
| "numeric", |
| "invalid", |
| "appearance", |
| "disabled", |
| "style", |
| ]) |
|
|
| let input: HTMLInputElement | undefined |
|
|
| return ( |
| <div |
| data-component="inline-input-v2" |
| data-disabled={local.disabled ? "" : undefined} |
| data-invalid={local.invalid ? "" : undefined} |
| data-numeric={local.numeric ? "" : undefined} |
| data-appearance={local.appearance ?? "base"} |
| data-label-width={local.labelWidth != null ? "" : undefined} |
| classList={{ |
| ...local.classList, |
| [local.class ?? ""]: !!local.class, |
| }} |
| style={{ |
| ...(typeof local.style === "object" && local.style != null ? local.style : {}), |
| ...(local.labelWidth != null |
| ? { |
| "--inline-input-v2-label-width": |
| typeof local.labelWidth === "number" ? `${local.labelWidth}px` : local.labelWidth, |
| } |
| : {}), |
| }} |
| > |
| <div |
| data-slot="inline-input-v2-prefix" |
| onMouseDown={(event) => { |
| if (local.disabled || event.button !== 0) return |
| // Keep focus on the input without using a native <label>, so external labels still work. |
| event.preventDefault() |
| input?.focus() |
| }} |
| > |
| <span data-slot="inline-input-v2-prefix-text">{local.prefix}</span> |
| </div> |
| <div data-slot="inline-input-v2-divider" aria-hidden="true" /> |
| <div data-slot="inline-input-v2-field"> |
| <div data-slot="inline-input-v2-value"> |
| <input |
| {...inputProps} |
| ref={(el) => { |
| input = el |
| const ref = inputProps.ref |
| if (typeof ref === "function") ref(el) |
| }} |
| type={inputProps.type ?? "text"} |
| disabled={local.disabled} |
| aria-invalid={local.invalid ? true : undefined} |
| data-slot="inline-input-v2-input" |
| /> |
| </div> |
| <Show when={local.showCopyButton}> |
| <button |
| type="button" |
| data-slot="inline-input-v2-icon-button" |
| aria-label={local.copyLabel ?? i18n.t("ui.message.copy")} |
| disabled={local.disabled} |
| onClick={local.onCopyClick} |
| > |
| <Icon name="copy" /> |
| </button> |
| </Show> |
| </div> |
| </div> |
| ) |
| } |
| |