diff --git a/.changeset/thirty-flowers-yell.md b/.changeset/thirty-flowers-yell.md
new file mode 100644
index 000000000..679c735ab
--- /dev/null
+++ b/.changeset/thirty-flowers-yell.md
@@ -0,0 +1,5 @@
+---
+"@orbit-ui/transition-components": minor
+---
+
+Added support for size prop on TextInput / SearchInput and PasswordInput
diff --git a/packages/components/src/input/src/Input.css b/packages/components/src/input/src/Input.css
index 09387109c..2ba793dcc 100644
--- a/packages/components/src/input/src/Input.css
+++ b/packages/components/src/input/src/Input.css
@@ -3,9 +3,12 @@
--o-ui-input-padding-with-icon: var(--hop-space-inset-xl);
--o-ui-input-padding-with-button: 2.5rem;
--o-ui-input-padding-loading: 2.5rem;
+ --o-ui-input-sm-padding: var(--hop-space-inset-squish-sm);
--o-ui-input-border-color: var(--hop-neutral-border);
--o-ui-input-border-radius: var(--hop-shape-rounded-md);
--o-ui-input-background-color: var(--hop-neutral-surface);
+ --o-ui-input-height: 2.5rem;
+ --o-ui-input-sm-height: 2rem;
}
.o-ui-input {
@@ -28,11 +31,15 @@
width: 100%;
background-color: inherit;
color: var(--hop-neutral-text);
- min-height: calc(2.5rem - 2px);
+ min-height: calc(var(--o-ui-input-height) - 2px);
margin: 0;
padding: 0;
}
+.o-ui-input-sm input {
+ min-height: calc(var(--o-ui-input-sm-height) - 2px);
+}
+
.o-ui-input textarea {
width: 100%;
}
@@ -59,12 +66,20 @@
font-family: inherit;
}
+.o-ui-text-input.o-ui-input-sm {
+ font-size: var(--hop-body-sm-font-size);
+}
+
.o-ui-text-input input,
.o-ui-text-area textarea,
.o-ui-number-input input {
padding: var(--o-ui-input-padding);
}
+.o-ui-text-input.o-ui-input-sm input {
+ padding: var(--o-ui-input-sm-padding);
+}
+
.o-ui-text-input input,
.o-ui-text-area {
border-radius: var(--o-ui-input-border-radius);
diff --git a/packages/components/src/input/src/useInput.ts b/packages/components/src/input/src/useInput.ts
index f27b9f01f..24c0d1463 100644
--- a/packages/components/src/input/src/useInput.ts
+++ b/packages/components/src/input/src/useInput.ts
@@ -1,5 +1,5 @@
import { ChangeEvent, ChangeEventHandler, ForwardedRef } from "react";
-import { cssModule, isNil, isNumber, mergeClasses, useAutoFocus, useEventCallback, useMergedRefs } from "../../shared";
+import { cssModule, isNil, isNumber, mergeClasses, normalizeSize, Size, useAutoFocus, useEventCallback, useMergedRefs } from "../../shared";
import { ValidationState } from "./types";
@@ -18,6 +18,7 @@ export interface UseInputProps {
placeholder?: string;
readOnly?: boolean;
required?: boolean;
+ size?: Size;
type?: "text" | "password" | "search" | "url" | "tel" | "email" | "number";
validationState?: ValidationState;
value?: string | number;
@@ -38,6 +39,7 @@ export function useInput({
placeholder,
readOnly,
required,
+ size,
type,
validationState,
value
@@ -81,7 +83,8 @@ export function useInput({
loading && "loading",
active && "active",
focus && "focus",
- hover && "hover"
+ hover && "hover",
+ normalizeSize(size)
)
),
role: "presentation"
diff --git a/packages/components/src/input/src/useInputContent.tsx b/packages/components/src/input/src/useInputContent.tsx
index 0689f474a..a9938cf13 100644
--- a/packages/components/src/input/src/useInputContent.tsx
+++ b/packages/components/src/input/src/useInputContent.tsx
@@ -1,5 +1,5 @@
import { embedIconButton } from "../../button";
-import { Spinner } from "../../spinner";
+import { Spinner, SpinnerProps } from "../../spinner";
import { CreatedIconProps } from "@hopper-ui/icons";
import { ReactElement } from "react";
import { augmentElement } from "../../shared";
@@ -21,6 +21,6 @@ export function useInputButton(button: ReactElement, isActive: boolean, props: R
});
}
-export function useInputSpinner(loading: boolean) {
- return loading && ;
+export function useInputSpinner(loading: boolean, props?: Partial) {
+ return loading && ;
}
diff --git a/packages/components/src/text-input/docs/TextInput.stories.mdx b/packages/components/src/text-input/docs/TextInput.stories.mdx
index 7e2c52612..f7405ba07 100644
--- a/packages/components/src/text-input/docs/TextInput.stories.mdx
+++ b/packages/components/src/text-input/docs/TextInput.stories.mdx
@@ -90,6 +90,19 @@ A text input can show that it is currently loading data.
+### Size
+
+A text input can vary in size.
+
+
+
+
+
+
+
+
+
+
### Fluid
A text input can take the width of its container.
diff --git a/packages/components/src/text-input/src/PasswordInput.tsx b/packages/components/src/text-input/src/PasswordInput.tsx
index 5e9479cd4..469ac776e 100644
--- a/packages/components/src/text-input/src/PasswordInput.tsx
+++ b/packages/components/src/text-input/src/PasswordInput.tsx
@@ -1,7 +1,8 @@
import { AbstractTextInputProps, TextInput } from "./TextInput";
import { useState, ChangeEvent, ComponentProps, forwardRef } from "react";
import { EyeVisibleIcon, EyeHiddenIcon } from "@hopper-ui/icons";
-import { OmitInternalProps, mergeProps, useControllableState, useEventCallback } from "../../shared";
+import { OmitInternalProps, mergeProps, createSizeAdapter, useControllableState, useEventCallback } from "../../shared";
+import { useResponsiveValue } from "../../styling";
import { IconButton } from "../../button";
import { useInputGroupTextInputProps } from "../../input-group";
@@ -10,6 +11,13 @@ const DefaultElement = "input";
export type InnerPasswordInputProps = AbstractTextInputProps;
+/* eslint-disable sort-keys, sort-keys-fix/sort-keys-fix */
+const buttonSize = createSizeAdapter({
+ "sm": "xs",
+ "md": "sm"
+});
+/* eslint-enable sort-keys, sort-keys-fix/sort-keys-fix */
+
export function InnerPasswordInput(props: InnerPasswordInputProps) {
const [inputGroupProps] = useInputGroupTextInputProps();
@@ -17,6 +25,7 @@ export function InnerPasswordInput(props: InnerPasswordInputProps) {
as = DefaultElement,
defaultValue,
forwardedRef,
+ size,
value,
wrapperProps,
...rest
@@ -28,6 +37,8 @@ export function InnerPasswordInput(props: InnerPasswordInputProps) {
const [inputValue, setValue] = useControllableState(value, defaultValue, "");
const [isHidden, setIsHidden] = useState(true);
+ const sizeValue = useResponsiveValue(size);
+
const handleChange = useEventCallback((event: ChangeEvent) => {
setValue(event.target.value);
});
@@ -42,7 +53,7 @@ export function InnerPasswordInput(props: InnerPasswordInputProps) {
aria-label="Toggle password visibility"
className="o-ui-password-input-show-button"
onClick={handleShowValue}
- size="sm"
+ size={buttonSize(sizeValue)}
title="Toggle password visibility"
variant="tertiary"
>
@@ -59,6 +70,7 @@ export function InnerPasswordInput(props: InnerPasswordInputProps) {
button: showButtonMarkup,
onChange: handleChange,
ref: forwardedRef,
+ size: size,
type: isHidden ? "password" as const : "text" as const,
value: inputValue,
wrapperProps: mergeProps(wrapperProps ?? {}, {
diff --git a/packages/components/src/text-input/src/SearchInput.tsx b/packages/components/src/text-input/src/SearchInput.tsx
index cff24fb83..b648dd4ad 100644
--- a/packages/components/src/text-input/src/SearchInput.tsx
+++ b/packages/components/src/text-input/src/SearchInput.tsx
@@ -40,6 +40,7 @@ export function InnerSearchInput(props: InnerSearchInputProps) {
onChange,
onKeyDown,
onValueChange,
+ size,
value,
wrapperProps,
...rest
@@ -111,6 +112,7 @@ export function InnerSearchInput(props: InnerSearchInputProps) {
onChange: handleChange,
onKeyDown: handleKeyDown,
ref: inputRef,
+ size: size,
spellCheck: "false",
type: "search" as const,
value: inputValue,
diff --git a/packages/components/src/text-input/src/TextInput.tsx b/packages/components/src/text-input/src/TextInput.tsx
index 6f58834c7..5e8913b7a 100644
--- a/packages/components/src/text-input/src/TextInput.tsx
+++ b/packages/components/src/text-input/src/TextInput.tsx
@@ -1,8 +1,8 @@
-import { AbstractInputProps, adaptInputStylingProps, useInput, useInputButton, useInputHasFocus, useInputIcon, useInputSpinner } from "../../input";
+import { AbstractInputProps, adaptInputStylingProps, useInput, useInputIcon, useInputSpinner, useInputButton, useInputHasFocus } from "../../input";
import { Box, BoxProps } from "../../box";
import { ChangeEvent, ComponentProps, ElementType, ReactElement, forwardRef } from "react";
import { ClearInputGroupContext, useInputGroupTextInputProps } from "../../input-group";
-import { OmitInternalProps, cssModule, isNil, mergeProps, omitProps, useChainedEventCallback, useControllableState } from "../../shared";
+import { OmitInternalProps, cssModule, createSizeAdapter, isNil, mergeProps, omitProps, useChainedEventCallback, useControllableState } from "../../shared";
import { ResponsiveProp, useResponsiveValue } from "../../styling";
import { useFieldInputProps } from "../../field";
import { useToolbarProps } from "../../toolbar";
@@ -35,6 +35,10 @@ export type AbstractTextInputProps = AbstractInputProps, value: string) => void;
+ /**
+ * An input can vary in size.
+ */
+ size?: ResponsiveProp<"sm" | "md">;
/**
* A controlled value.
*/
@@ -54,6 +58,20 @@ export interface InnerTextInputProps extends AbstractTextInputProps
@@ -189,7 +212,6 @@ export function InnerTextInput(props: InnerTextInputProps) {
);
}
-InnerTextInput.defaultElement = DefaultElement;
/**
* A text input allow a user to enter and edit a text.
diff --git a/packages/components/src/text-input/tests/chromatic/PasswordInput.stories.tsx b/packages/components/src/text-input/tests/chromatic/PasswordInput.stories.tsx
index 83fbbf3f7..3dddf4b18 100644
--- a/packages/components/src/text-input/tests/chromatic/PasswordInput.stories.tsx
+++ b/packages/components/src/text-input/tests/chromatic/PasswordInput.stories.tsx
@@ -14,7 +14,10 @@ export const Default: PasswordInputStory = {
storyName: "default",
render: () => (
-
+
+
+
+
@@ -29,7 +32,10 @@ export const Placeholder: PasswordInputStory = {
storyName: "placeholder",
render: () => (
-
+
+
+
+
@@ -44,7 +50,10 @@ export const Value: PasswordInputStory = {
storyName: "value",
render: () => (
-
+
+
+
+
@@ -87,10 +96,16 @@ export const Zoom: PasswordInputStory = {
render: () => (
)
diff --git a/packages/components/src/text-input/tests/chromatic/SearchInput.stories.tsx b/packages/components/src/text-input/tests/chromatic/SearchInput.stories.tsx
index 257a2615c..8ed0b345f 100644
--- a/packages/components/src/text-input/tests/chromatic/SearchInput.stories.tsx
+++ b/packages/components/src/text-input/tests/chromatic/SearchInput.stories.tsx
@@ -16,8 +16,14 @@ export const Default: SearchInputStory = {
storyName: "default",
render: () => (
-
-
+
+
+
+
+
+
+
+
@@ -25,7 +31,7 @@ export const Default: SearchInputStory = {
-
+
)
};
@@ -33,7 +39,10 @@ export const Placeholder: SearchInputStory = {
storyName: "placeholder",
render: () => (
-
+
+
+
+
@@ -50,7 +59,10 @@ export const Value: SearchInputStory = {
storyName: "value",
render: () => (
-
+
+
+
+
@@ -71,7 +83,10 @@ export const CustomIcon: SearchInputStory = {
storyName: "custom icon",
render: () => (
- } placeholder="Where to?" aria-label="Label" />
+
+ } placeholder="Where to?" aria-label="Label" />
+ } placeholder="Where to?" aria-label="Label" size="sm" />
+
} defaultValue="SpaceX will win the race!" aria-label="Label" />
} placeholder="Where to?" />
} placeholder="Where to?" />
@@ -132,10 +147,16 @@ export const Zoom: SearchInputStory = {
render: () => (
-
+
+
+
+
-
+
+
+
+
)
diff --git a/packages/components/src/text-input/tests/chromatic/TextInput.stories.tsx b/packages/components/src/text-input/tests/chromatic/TextInput.stories.tsx
index 3783161be..e66b57352 100644
--- a/packages/components/src/text-input/tests/chromatic/TextInput.stories.tsx
+++ b/packages/components/src/text-input/tests/chromatic/TextInput.stories.tsx
@@ -17,9 +17,15 @@ export const Default: TextInputStory = {
storyName: "default",
render: () => (
-
+
+
+
+
-
+
+
+
+
@@ -35,7 +41,10 @@ export const Placeholder: TextInputStory = {
storyName: "placeholder",
render: () => (
-
+
+
+
+
@@ -53,7 +62,10 @@ export const Value: TextInputStory = {
storyName: "value",
render: () => (
-
+
+
+
+
@@ -75,7 +87,10 @@ export const Icon: TextInputStory = {
storyName: "icon",
render: () => (
- } placeholder="Where to?" aria-label="Label" />
+
+ } placeholder="Where to?" aria-label="Label" />
+ } placeholder="Where to?" aria-label="Label" size="sm" />
+
} defaultValue="SpaceX will win the race!" placeholder="Where to?" />
} placeholder="Where to?" />
} placeholder="Where to?" />
@@ -93,7 +108,10 @@ export const Button: TextInputStory = {
storyName: "button",
render: () => (
- } placeholder="Where to?" />
+
+ } placeholder="Where to?" />
+ } placeholder="Where to?" size="sm" />
+
} placeholder="Where to?" defaultValue="SpaceX will win the race!" />
} placeholder="Where to?" />
@@ -153,10 +171,16 @@ export const Zoom: TextInputStory = {
render: () => (
-
+
+
+
+
-
+
+
+
+
)