move ghosttext component to textfield
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import {createContext, useContext, useMemo, useRef} from 'react'
|
||||
import {
|
||||
type AccessibilityProps,
|
||||
StyleSheet,
|
||||
@@ -16,7 +16,9 @@ import {
|
||||
applyFonts,
|
||||
atoms as a,
|
||||
ios,
|
||||
platform,
|
||||
type TextStyleProp,
|
||||
tokens,
|
||||
useAlf,
|
||||
useTheme,
|
||||
web,
|
||||
@@ -25,7 +27,7 @@ import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||
import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
const Context = React.createContext<{
|
||||
const Context = createContext<{
|
||||
inputRef: React.RefObject<TextInput> | null
|
||||
isInvalid: boolean
|
||||
hovered: boolean
|
||||
@@ -48,7 +50,7 @@ const Context = React.createContext<{
|
||||
export type RootProps = React.PropsWithChildren<{isInvalid?: boolean}>
|
||||
|
||||
export function Root({children, isInvalid = false}: RootProps) {
|
||||
const inputRef = React.useRef<TextInput>(null)
|
||||
const inputRef = useRef<TextInput>(null)
|
||||
const {
|
||||
state: hovered,
|
||||
onIn: onHoverIn,
|
||||
@@ -56,7 +58,7 @@ export function Root({children, isInvalid = false}: RootProps) {
|
||||
} = useInteractionState()
|
||||
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
|
||||
|
||||
const context = React.useMemo(
|
||||
const context = useMemo(
|
||||
() => ({
|
||||
inputRef,
|
||||
hovered,
|
||||
@@ -96,7 +98,7 @@ export function Root({children, isInvalid = false}: RootProps) {
|
||||
|
||||
export function useSharedInputStyles() {
|
||||
const t = useTheme()
|
||||
return React.useMemo(() => {
|
||||
return useMemo(() => {
|
||||
const hover: ViewStyle[] = [
|
||||
{
|
||||
borderColor: t.palette.contrast_100,
|
||||
@@ -158,7 +160,7 @@ export function createInput(Component: typeof TextInput) {
|
||||
}: InputProps) {
|
||||
const t = useTheme()
|
||||
const {fonts} = useAlf()
|
||||
const ctx = React.useContext(Context)
|
||||
const ctx = useContext(Context)
|
||||
const withinRoot = Boolean(ctx.inputRef)
|
||||
|
||||
const {chromeHover, chromeFocus, chromeError, chromeErrorHover} =
|
||||
@@ -283,8 +285,8 @@ export function LabelText({
|
||||
|
||||
export function Icon({icon: Comp}: {icon: React.ComponentType<SVGIconProps>}) {
|
||||
const t = useTheme()
|
||||
const ctx = React.useContext(Context)
|
||||
const {hover, focus, errorHover, errorFocus} = React.useMemo(() => {
|
||||
const ctx = useContext(Context)
|
||||
const {hover, focus, errorHover, errorFocus} = useMemo(() => {
|
||||
const hover: TextStyle[] = [
|
||||
{
|
||||
color: t.palette.contrast_800,
|
||||
@@ -342,7 +344,7 @@ export function SuffixText({
|
||||
}
|
||||
>) {
|
||||
const t = useTheme()
|
||||
const ctx = React.useContext(Context)
|
||||
const ctx = useContext(Context)
|
||||
return (
|
||||
<Text
|
||||
accessibilityLabel={label}
|
||||
@@ -362,3 +364,67 @@ export function SuffixText({
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
export function GhostText({
|
||||
children,
|
||||
value,
|
||||
}: {
|
||||
children: string
|
||||
value: string
|
||||
}) {
|
||||
const t = useTheme()
|
||||
// eslint-disable-next-line bsky-internal/avoid-unwrapped-text
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
a.pointer_events_none,
|
||||
a.absolute,
|
||||
a.z_10,
|
||||
{
|
||||
paddingLeft: platform({
|
||||
native:
|
||||
// input padding
|
||||
tokens.space.md +
|
||||
// icon
|
||||
tokens.space.xl +
|
||||
// icon padding
|
||||
tokens.space.xs +
|
||||
// text input padding
|
||||
tokens.space.xs,
|
||||
web:
|
||||
// icon
|
||||
tokens.space.xl +
|
||||
// icon padding
|
||||
tokens.space.xs +
|
||||
// text input padding
|
||||
tokens.space.xs,
|
||||
}),
|
||||
},
|
||||
web(a.pr_md),
|
||||
a.overflow_hidden,
|
||||
a.max_w_full,
|
||||
]}
|
||||
aria-hidden={true}
|
||||
accessibilityElementsHidden
|
||||
importantForAccessibility="no-hide-descendants">
|
||||
<Text
|
||||
style={[
|
||||
{color: 'transparent'},
|
||||
a.text_md,
|
||||
{lineHeight: a.text_md.fontSize * 1.1875},
|
||||
a.w_full,
|
||||
]}
|
||||
numberOfLines={1}>
|
||||
{children}
|
||||
<Text
|
||||
style={[
|
||||
t.atoms.text_contrast_low,
|
||||
a.text_md,
|
||||
{lineHeight: a.text_md.fontSize * 1.1875},
|
||||
]}>
|
||||
{value}
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import {useHandleAvailabilityQuery} from '#/state/queries/handle-availablility'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {ScreenTransition} from '#/screens/Login/ScreenTransition'
|
||||
import {useSignupContext} from '#/screens/Signup/state'
|
||||
import {atoms as a, platform, tokens, useTheme, web} from '#/alf'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import * as TextField from '#/components/forms/TextField'
|
||||
import {useThrottledValue} from '#/components/hooks/useThrottledValue'
|
||||
import {At_Stroke2_Corner0_Rounded as AtIcon} from '#/components/icons/At'
|
||||
@@ -152,9 +152,10 @@ export function StepHandle() {
|
||||
autoFocus
|
||||
autoComplete="off"
|
||||
/>
|
||||
|
||||
{draftValue.length > 0 && (
|
||||
<GhostText value={state.userDomain}>{draftValue}</GhostText>
|
||||
<TextField.GhostText value={state.userDomain}>
|
||||
{draftValue}
|
||||
</TextField.GhostText>
|
||||
)}
|
||||
</TextField.Root>
|
||||
</View>
|
||||
@@ -297,61 +298,3 @@ function RequirementIcon({
|
||||
return <Loader size="sm" style={t.atoms.text_contrast_low} />
|
||||
}
|
||||
}
|
||||
|
||||
function GhostText({children, value}: {children: string; value: string}) {
|
||||
const t = useTheme()
|
||||
// eslint-disable-next-line bsky-internal/avoid-unwrapped-text
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
a.pointer_events_none,
|
||||
a.absolute,
|
||||
a.z_10,
|
||||
{
|
||||
paddingLeft: platform({
|
||||
native:
|
||||
// input padding
|
||||
tokens.space.md +
|
||||
// icon
|
||||
tokens.space.xl +
|
||||
// icon padding
|
||||
tokens.space.xs +
|
||||
// text input padding
|
||||
tokens.space.xs,
|
||||
web:
|
||||
// icon
|
||||
tokens.space.xl +
|
||||
// icon padding
|
||||
tokens.space.xs +
|
||||
// text input padding
|
||||
tokens.space.xs,
|
||||
}),
|
||||
},
|
||||
web(a.pr_md),
|
||||
a.overflow_hidden,
|
||||
a.max_w_full,
|
||||
]}
|
||||
aria-hidden={true}
|
||||
accessibilityElementsHidden
|
||||
importantForAccessibility="no-hide-descendants">
|
||||
<Text
|
||||
style={[
|
||||
{color: 'transparent'},
|
||||
a.text_md,
|
||||
{lineHeight: a.text_md.fontSize * 1.1875},
|
||||
a.w_full,
|
||||
]}
|
||||
numberOfLines={1}>
|
||||
{children}
|
||||
<Text
|
||||
style={[
|
||||
t.atoms.text_contrast_low,
|
||||
a.text_md,
|
||||
{lineHeight: a.text_md.fontSize * 1.1875},
|
||||
]}>
|
||||
{value}
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user