update from cdrl
This commit is contained in:
@@ -107,8 +107,9 @@ export interface FormInputProps
|
||||
extends
|
||||
FormInputCommonProps,
|
||||
Pick<JSX.InputHTMLAttributes<HTMLInputElement>, CommonInputAttrs | "type" | "max" | "min" | "step" | "accept"> {
|
||||
small?: boolean;
|
||||
ref?: (el: HTMLInputElement) => void;
|
||||
prefix?: JSXElement;
|
||||
small?: boolean;
|
||||
class?: string;
|
||||
onDark?: boolean;
|
||||
}
|
||||
@@ -121,10 +122,6 @@ export interface FormTextareaProps
|
||||
onDark?: boolean;
|
||||
}
|
||||
|
||||
export interface FormInputGroupProps extends FormInputProps {
|
||||
prefix?: JSXElement;
|
||||
}
|
||||
|
||||
export interface FormNumberInputProps extends FormInputProps {
|
||||
int?: boolean;
|
||||
unsigned?: boolean;
|
||||
@@ -171,7 +168,7 @@ function _comboboxRootCls(className?: string, fieldWidth: ComboboxFieldWidth = "
|
||||
}
|
||||
|
||||
export interface FormComboboxProps extends Pick<JSX.SelectHTMLAttributes<HTMLSelectElement>, CommonSelectAttrs> {
|
||||
options: FormSelectOption[];
|
||||
options?: FormSelectOption[];
|
||||
placeholder?: string;
|
||||
searchable?: boolean;
|
||||
searchPlaceholder?: string;
|
||||
@@ -227,90 +224,104 @@ export interface FormMultiSelectTriggerProps {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
export function FormInput(props: FormInputProps) {
|
||||
const cls = () => _inputCls(props.small, props.error, props.success, props.class, props.onDark);
|
||||
const inputValue = () => readAccessor(props.value, "");
|
||||
return <div class="ui-form">
|
||||
<input
|
||||
ref={(el) => typeof props.ref === "function" && props.ref(el)}
|
||||
class={cls()}
|
||||
type={props.type}
|
||||
value={inputValue()}
|
||||
placeholder={props.placeholder}
|
||||
autocomplete={props.autocomplete || (props.passwordManagerIgnore ? "off" : undefined)}
|
||||
inputmode={props.inputmode}
|
||||
data-1p-ignore={props.passwordManagerIgnore}
|
||||
data-lpignore={props.passwordManagerIgnore ? "other" : undefined}
|
||||
data-form-type={props.passwordManagerIgnore}
|
||||
data-bwignore={props.passwordManagerIgnore}
|
||||
data-protonpass-ignore={props.passwordManagerIgnore}
|
||||
disabled={props.disabled}
|
||||
maxlength={props.maxlength}
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
step={props.step}
|
||||
name={props.name}
|
||||
id={props.id}
|
||||
oninput={props.oninput}
|
||||
onchange={props.onchange}
|
||||
onBlur={props.onblur}
|
||||
onFocus={props.onfocus}
|
||||
onKeyDown={props.onkeydown}
|
||||
|
||||
/>
|
||||
<Show when={props.error}>
|
||||
<span class={FORM_ERROR}>{props.error}</span>
|
||||
</Show>
|
||||
<Show when={props.success}>
|
||||
<span class={FORM_SUCCESS}>{props.success}</span>
|
||||
</Show>
|
||||
</div>;
|
||||
export function FormInputOld(props: FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, [
|
||||
"prefix",
|
||||
"small",
|
||||
"error",
|
||||
"success",
|
||||
"class",
|
||||
"onDark",
|
||||
"ref",
|
||||
"autocomplete",
|
||||
"passwordManagerIgnore",
|
||||
]);
|
||||
|
||||
return (
|
||||
<div class="ui-form">
|
||||
<input
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
class={_inputCls(local.small, local.error, local.success, local.class, local.onDark)}
|
||||
autocomplete={local.autocomplete || (local.passwordManagerIgnore ? "off" : undefined)}
|
||||
data-1p-ignore={local.passwordManagerIgnore}
|
||||
data-lpignore={local.passwordManagerIgnore ? "other" : undefined}
|
||||
data-form-type={local.passwordManagerIgnore}
|
||||
data-bwignore={local.passwordManagerIgnore}
|
||||
data-protonpass-ignore={local.passwordManagerIgnore}
|
||||
{...inputProps}
|
||||
/>
|
||||
<Show when={local.error}>
|
||||
<span class={FORM_ERROR}>{local.error}</span>
|
||||
</Show>
|
||||
<Show when={local.success}>
|
||||
<span class={FORM_SUCCESS}>{local.success}</span>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function FormInputGroup(props: FormInputGroupProps) {
|
||||
const pfxCls = () => _prefixCls(props.small, props.error, props.onDark);
|
||||
const inputCls = () => _inputCls(props.small, props.error, props.success, "rounded-l-none" + (props.class ? " " + props.class : ""), props.onDark);
|
||||
const inputValue = () => readAccessor(props.value, "");
|
||||
return <div class="ui-form">
|
||||
<div class={INPUT_GROUP}>
|
||||
<span class={pfxCls()}>{props.prefix}</span>
|
||||
<span class="grow flex">
|
||||
<input
|
||||
ref={(el) => typeof props.ref === "function" && props.ref(el)}
|
||||
class={inputCls()}
|
||||
type={props.type}
|
||||
value={inputValue()}
|
||||
placeholder={props.placeholder}
|
||||
autocomplete={props.autocomplete || (props.passwordManagerIgnore ? "off" : undefined)}
|
||||
inputmode={props.inputmode}
|
||||
data-1p-ignore={props.passwordManagerIgnore}
|
||||
data-lpignore={props.passwordManagerIgnore ? "other" : undefined}
|
||||
data-form-type={props.passwordManagerIgnore}
|
||||
data-bwignore={props.passwordManagerIgnore}
|
||||
data-protonpass-ignore={props.passwordManagerIgnore}
|
||||
disabled={props.disabled}
|
||||
maxlength={props.maxlength}
|
||||
name={props.name}
|
||||
id={props.id}
|
||||
oninput={props.oninput}
|
||||
onchange={props.onchange}
|
||||
onBlur={props.onblur}
|
||||
onFocus={props.onfocus}
|
||||
onKeyDown={props.onkeydown}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<Show when={props.error}>
|
||||
<span class={FORM_ERROR}>{props.error}</span>
|
||||
export function FormInput(props: FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, [
|
||||
"prefix",
|
||||
"small",
|
||||
"error",
|
||||
"success",
|
||||
"class",
|
||||
"onDark",
|
||||
"ref",
|
||||
"autocomplete",
|
||||
"passwordManagerIgnore",
|
||||
]);
|
||||
|
||||
const cls = local.prefix ? ("rounded-l-none" + (local.class ? " " + local.class : "")) : local.class;
|
||||
|
||||
const InputEl = () => (
|
||||
<input
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
class={_inputCls(local.small, local.error, local.success, cls, local.onDark)}
|
||||
autocomplete={local.autocomplete || (local.passwordManagerIgnore ? "off" : undefined)}
|
||||
data-1p-ignore={local.passwordManagerIgnore}
|
||||
data-lpignore={local.passwordManagerIgnore ? "other" : undefined}
|
||||
data-form-type={local.passwordManagerIgnore}
|
||||
data-bwignore={local.passwordManagerIgnore}
|
||||
data-protonpass-ignore={local.passwordManagerIgnore}
|
||||
{...inputProps}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Show
|
||||
when={local.prefix}
|
||||
fallback={
|
||||
<div class="ui-form">
|
||||
<InputEl />
|
||||
<Show when={local.error}>
|
||||
<span class={FORM_ERROR}>{local.error}</span>
|
||||
</Show>
|
||||
<Show when={local.success}>
|
||||
<span class={FORM_SUCCESS}>{local.success}</span>
|
||||
</Show>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div class="ui-form">
|
||||
<div class={INPUT_GROUP}>
|
||||
<span class={_prefixCls(local.small, local.error, local.onDark)}>{local.prefix}</span>
|
||||
<span class="grow flex"><InputEl /></span>
|
||||
</div>
|
||||
<Show when={local.error}>
|
||||
<span class={FORM_ERROR}>{local.error}</span>
|
||||
</Show>
|
||||
<Show when={local.success}>
|
||||
<span class={FORM_SUCCESS}>{local.success}</span>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={props.success}>
|
||||
<span class={FORM_SUCCESS}>{props.success}</span>
|
||||
</Show>
|
||||
</div>;
|
||||
);
|
||||
}
|
||||
|
||||
export function FormNumberInput(props: FormNumberInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["small", "ref", "class", "oninput", "int", "unsigned"]);
|
||||
const [local, inputProps] = splitProps(props, ["oninput", "int", "unsigned"]);
|
||||
var regex: RegExp;
|
||||
|
||||
if (local.int) {
|
||||
@@ -339,45 +350,11 @@ export function FormNumberInput(props: FormNumberInputProps) {
|
||||
}
|
||||
};
|
||||
|
||||
return <FormInput
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
oninput={handleInput}
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
{...inputProps}
|
||||
/>;
|
||||
return <FormInput inputMode="decimal" oninput={handleInput} {...inputProps} />;
|
||||
}
|
||||
|
||||
export function FormCarNumberInput(props: FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["small", "ref", "class", "oninput"]);
|
||||
|
||||
const handleInput = (e) => {
|
||||
if (!e || !e.currentTarget) return;
|
||||
const input = e.currentTarget;
|
||||
const raw = input.value.toUpperCase().replace(/[^0-9A-Z]/g, "");
|
||||
const match = raw.match(/^([0-9]{0,2})([A-Z]{0,2})/);
|
||||
input.value = match ? match[1] + match[2] : "";
|
||||
if (typeof local.oninput === "function") {
|
||||
local.oninput(e);
|
||||
}
|
||||
};
|
||||
|
||||
return <FormInput
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
type="text"
|
||||
maxLength="4"
|
||||
oninput={handleInput}
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
placeholder="e.g. 28"
|
||||
{...inputProps}
|
||||
/>;
|
||||
}
|
||||
|
||||
export function FormCurrencyInput(props: {hideSymbol?: boolean} & FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["small", "ref", "class", "oninput", "hideSymbol"]);
|
||||
export function FormCurrencyInput(props: {showIcon?: boolean} & FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["oninput", "showIcon"]);
|
||||
|
||||
const handleInput = (e) => {
|
||||
if (!e || !e.currentTarget) return;
|
||||
@@ -396,32 +373,12 @@ export function FormCurrencyInput(props: {hideSymbol?: boolean} & FormInputProp
|
||||
}
|
||||
};
|
||||
|
||||
if (local.hideSymbol) {
|
||||
return <FormInput
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
oninput={handleInput}
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
{...inputProps}
|
||||
/>;
|
||||
} else {
|
||||
return <FormInputGroup
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
prefix="$"
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
oninput={handleInput}
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
{...inputProps}
|
||||
/>;
|
||||
}
|
||||
return <FormInput prefix={local.showIcon ? "$" : null} inputMode="decimal" oninput={handleInput} {...inputProps} />;
|
||||
|
||||
}
|
||||
|
||||
export function FormPercentInput(props: FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["small", "ref", "class", "oninput"]);
|
||||
export function FormPercentInput(props: {showIcon?: boolean} & FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["oninput", "showIcon"]);
|
||||
|
||||
const handleInput = (e) => {
|
||||
if (!e || !e.currentTarget) return;
|
||||
@@ -436,20 +393,11 @@ export function FormPercentInput(props: FormInputProps) {
|
||||
}
|
||||
};
|
||||
|
||||
return <FormInputGroup
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
prefix="%"
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
oninput={handleInput}
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
{...inputProps}
|
||||
/>;
|
||||
return <FormInput prefix={local.showIcon ? "%" : null} inputMode="decimal" oninput={handleInput} {...inputProps} />;
|
||||
}
|
||||
|
||||
export function FormPhoneInput(props: FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["small", "ref", "class", "oninput"]);
|
||||
export function FormPhoneInput(props: {showIcon?: boolean; icon?: string} & FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["showIcon", "icon", "oninput"]);
|
||||
|
||||
const handleInput = (e) => {
|
||||
if (!e || !e.currentTarget) return;
|
||||
@@ -473,138 +421,45 @@ export function FormPhoneInput(props: FormInputProps) {
|
||||
}
|
||||
};
|
||||
|
||||
return <FormInput
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
oninput={handleInput}
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
placeholder="(555) 555-5555"
|
||||
{...inputProps}
|
||||
/>;
|
||||
}
|
||||
|
||||
// @TODO replace this with showIcon prop
|
||||
export function FormPhoneInputWithIcon(props: {icon?: string} & FormInputGroupProps) {
|
||||
const [local, inputProps] = splitProps(props, ["icon", "small", "ref", "class", "oninput"]);
|
||||
|
||||
const handleInput = (e) => {
|
||||
if (!e || !e.currentTarget) return;
|
||||
const input = e.currentTarget;
|
||||
let digits = input.value.replace(/\D/g, "");
|
||||
digits = digits.slice(0, 10);
|
||||
let formatted = "";
|
||||
if (digits.length > 0) {
|
||||
formatted = "(" + digits.slice(0, 3);
|
||||
}
|
||||
if (digits.length > 3) {
|
||||
formatted += ") " + digits.slice(3, 6);
|
||||
}
|
||||
if (digits.length > 6) {
|
||||
formatted += "-" + digits.slice(6, 10);
|
||||
}
|
||||
input.value = formatted;
|
||||
if (typeof local.oninput === "function") {
|
||||
local.oninput(e);
|
||||
}
|
||||
};
|
||||
|
||||
const iconEl = <IconInline icon={local.icon || "phone"} size={16} />;
|
||||
|
||||
return <FormInputGroup
|
||||
prefix={iconEl}
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
oninput={handleInput}
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
placeholder="(555) 555-5555"
|
||||
{...inputProps}
|
||||
/>;
|
||||
return (
|
||||
<FormInput
|
||||
prefix={local.showIcon !== false ? <IconInline icon={local.icon || "phone"} size={16} /> : null}
|
||||
inputMode="numeric"
|
||||
oninput={handleInput}
|
||||
placeholder="(555) 555-5555"
|
||||
{...inputProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function FormEmailInput(props: {showIcon?: boolean} & FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["showIcon", "small", "ref", "class", "error", "success", "onDark"]);
|
||||
const showIcon = () => local.showIcon !== false;
|
||||
const pfxCls = () => _prefixCls(local.small, local.error, local.onDark);
|
||||
const inputCls = () => _inputCls(local.small, local.error, local.success, "rounded-l-none" + (local.class ? " " + local.class : ""), local.onDark);
|
||||
const [local, inputProps] = splitProps(props, ["showIcon"]);
|
||||
|
||||
return <Show when={showIcon()} fallback={
|
||||
return (
|
||||
<FormInput
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
prefix={local.showIcon !== false ? <IconInline icon="envelope" size={16} /> : null}
|
||||
type="email"
|
||||
inputMode="email"
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
error={local.error}
|
||||
success={local.success}
|
||||
onDark={local.onDark}
|
||||
{...inputProps}
|
||||
/>}>
|
||||
<div class="ui-form">
|
||||
<div class={INPUT_GROUP}>
|
||||
<span class={pfxCls()}>
|
||||
<IconInline icon="envelope" size={16} />
|
||||
</span>
|
||||
<span class="grow flex">
|
||||
<input
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
type="email"
|
||||
inputMode="email"
|
||||
class={inputCls()}
|
||||
{...inputProps}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<Show when={local.error}>
|
||||
<span class={FORM_ERROR}>{local.error}</span>
|
||||
</Show>
|
||||
<Show when={local.success}>
|
||||
<span class={FORM_SUCCESS}>{local.success}</span>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>;
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function FormURLInput(props: {showIcon: boolean} & FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["showIcon", "small", "ref", "class", "onDark"]);
|
||||
const showIcon = () => local.showIcon !== false;
|
||||
const pfxCls = () => _prefixCls(local.small, false, local.onDark);
|
||||
const inputCls = () => _inputCls(local.small, false, false, "rounded-l-none" + (local.class ? " " + local.class : ""), local.onDark);
|
||||
export function FormURLInput(props: {showIcon?: boolean} & FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["showIcon"]);
|
||||
|
||||
return <Show when={showIcon()} fallback={
|
||||
return (
|
||||
<FormInput
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
prefix={local.showIcon !== false ? <IconInline icon="globe" size={16} /> : null}
|
||||
type="text"
|
||||
inputMode="url"
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
onDark={local.onDark}
|
||||
{...inputProps}
|
||||
/>}>
|
||||
<div class="ui-form">
|
||||
<div class={INPUT_GROUP}>
|
||||
<span class={pfxCls()}>
|
||||
<IconInline icon="globe" size={16} />
|
||||
</span>
|
||||
<span class="grow flex">
|
||||
<input
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
type="text"
|
||||
inputMode="url"
|
||||
class={inputCls()}
|
||||
{...inputProps}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Show>;
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function FormZipCodeInput(props: FormInputProps) {
|
||||
const [local, inputProps] = splitProps(props, ["small", "ref", "class", "oninput"]);
|
||||
const [local, inputProps] = splitProps(props, ["oninput"]);
|
||||
|
||||
const handleInput = (e) => {
|
||||
if (!e || !e.currentTarget) return;
|
||||
@@ -617,18 +472,15 @@ export function FormZipCodeInput(props: FormInputProps) {
|
||||
return b ? a + "-" + b : a;
|
||||
});
|
||||
|
||||
if (typeof props.oninput === "function") {
|
||||
props.oninput(e);
|
||||
if (typeof local.oninput === "function") {
|
||||
local.oninput(e);
|
||||
}
|
||||
};
|
||||
|
||||
return <FormInput
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
oninput={handleInput}
|
||||
class={local.class}
|
||||
small={local.small}
|
||||
placeholder="12345"
|
||||
{...inputProps}
|
||||
/>;
|
||||
@@ -807,7 +659,6 @@ export function FormSignaturePad(props: { value?: () => string; onchange?: (svg:
|
||||
// @TODO Fix this
|
||||
export function FormSelect(props: FormSelectProps & { children?: JSXElement }) {
|
||||
const [local, selectProps] = splitProps(props, ["small", "ref", "class", "children", "value", "onDark"]);
|
||||
const cls = () => _inputCls(local.small, false, false, local.class, local.onDark);
|
||||
let selectEl;
|
||||
// Set value via deferred effect so it runs AFTER children (<option>s) are in the DOM.
|
||||
// The spread's createRenderEffect runs immediately (before children), so select.value
|
||||
@@ -823,7 +674,7 @@ export function FormSelect(props: FormSelectProps & { children?: JSXElement }) {
|
||||
return <div class="ui-form">
|
||||
<select
|
||||
ref={(el) => { selectEl = el; if (local.ref) local.ref(el); }}
|
||||
class={cls()}
|
||||
class={_inputCls(local.small, false, false, local.class, local.onDark)}
|
||||
{...selectProps}
|
||||
>{local.children}</select>
|
||||
</div>;
|
||||
@@ -967,24 +818,23 @@ export function FormSearchableSelect(props: {ref: string} & FormComboboxProps) {
|
||||
}
|
||||
|
||||
export function FormTextarea(props: FormTextareaProps) {
|
||||
const cls = () => _textareaCls(props.small, props.error, props.class, props.onDark);
|
||||
const inputValue = () => readAccessor(props.value, "");
|
||||
const [local, inputProps] = splitProps(props, [
|
||||
"small",
|
||||
"error",
|
||||
"class",
|
||||
"onDark",
|
||||
"ref",
|
||||
]);
|
||||
|
||||
const cls = () => _textareaCls(local.small, local.error, local.class, local.onDark);
|
||||
return <div class="ui-form">
|
||||
<textarea
|
||||
ref={(el) => typeof props.ref === "function" && props.ref(el)}
|
||||
ref={(el) => typeof local.ref === "function" && local.ref(el)}
|
||||
class={cls()}
|
||||
value={inputValue()}
|
||||
placeholder={props.placeholder}
|
||||
rows={props.rows}
|
||||
disabled={props.disabled}
|
||||
name={props.name}
|
||||
id={props.id}
|
||||
oninput={props.oninput}
|
||||
onchange={props.onchange}
|
||||
onblur={props.onblur}
|
||||
{...inputProps}
|
||||
/>
|
||||
<Show when={props.error}>
|
||||
<span class={FORM_ERROR}>{props.error}</span>
|
||||
<Show when={local.error}>
|
||||
<span class={FORM_ERROR}>{local.error}</span>
|
||||
</Show>
|
||||
</div>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user