-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: pulled out TextField into separate components (#1744)
* fix: pulled out TextField into separate components * fix: updated docs for custom text fields * fix: restricted password to only allow specific auto-complete types * fix: removed errorMessage and hint from SearchField * fix: password field has label * fix: internal FieldLabel uses ScreenReaderText * fix(odyssey-storybook): args for SearchField stories match the component
- Loading branch information
1 parent
d494fe3
commit 0b7a412
Showing
19 changed files
with
816 additions
and
337 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/*! | ||
* Copyright (c) 2022-present, Okta, Inc. and/or its affiliates. All rights reserved. | ||
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") | ||
* | ||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* | ||
* See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
import { memo, ReactElement, useMemo } from "react"; | ||
|
||
import { | ||
FieldError, | ||
FieldHint, | ||
FieldLabel, | ||
FormControl, | ||
useUniqueId, | ||
} from "./"; | ||
|
||
export type FieldProps = { | ||
/** | ||
* If `error` is not undefined, the `input` will indicate an error. | ||
*/ | ||
errorMessage?: string; | ||
hasVisibleLabel: boolean; | ||
/** | ||
* The helper text content. | ||
*/ | ||
hint?: string; | ||
/** | ||
* The id of the `input` element. | ||
*/ | ||
id?: string; | ||
/** | ||
* If `true`, the component is disabled. | ||
*/ | ||
isDisabled?: boolean; | ||
/** | ||
* If `true`, the `input` element is required. | ||
*/ | ||
isRequired?: boolean; | ||
/** | ||
* The label for the `input` element. | ||
*/ | ||
label: string; | ||
/** | ||
* The label for the `input` element if the it's not optional | ||
*/ | ||
optionalLabel?: string; | ||
/** | ||
* The short hint displayed in the `input` before the user enters a value. | ||
*/ | ||
placeholder?: string; | ||
renderFieldComponent: ({ | ||
ariaDescribedBy, | ||
id, | ||
}: { | ||
ariaDescribedBy?: string; | ||
id: string; | ||
}) => ReactElement; | ||
}; | ||
|
||
const Field = ({ | ||
errorMessage, | ||
hasVisibleLabel, | ||
hint, | ||
id: idOverride, | ||
isDisabled = false, | ||
isRequired = true, | ||
label, | ||
optionalLabel, | ||
renderFieldComponent, | ||
}: FieldProps) => { | ||
const id = useUniqueId(idOverride); | ||
const hintId = hint ? `${id}-hint` : undefined; | ||
const errorId = errorMessage ? `${id}-error` : undefined; | ||
const labelId = `${id}-label`; | ||
|
||
const ariaDescribedBy = useMemo( | ||
() => [hintId, errorId].join(" ").trim() || undefined, | ||
[errorId, hintId] | ||
); | ||
|
||
return ( | ||
<FormControl disabled={isDisabled} error={Boolean(errorMessage)}> | ||
<FieldLabel | ||
hasVisibleLabel={hasVisibleLabel} | ||
id={labelId} | ||
inputId={id} | ||
isRequired={isRequired} | ||
optionalText={optionalLabel} | ||
text={label} | ||
/> | ||
|
||
{hint && <FieldHint id={hintId} text={hint} />} | ||
|
||
{renderFieldComponent({ | ||
ariaDescribedBy, | ||
id, | ||
})} | ||
|
||
{errorMessage && <FieldError id={errorId} text={errorMessage} />} | ||
</FormControl> | ||
); | ||
}; | ||
|
||
const MemoizedField = memo(Field); | ||
|
||
export { MemoizedField as Field }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/*! | ||
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved. | ||
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") | ||
* | ||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* | ||
* See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
import { memo } from "react"; | ||
|
||
import { FormHelperText } from "."; | ||
import { ScreenReaderText } from "./ScreenReaderText"; | ||
|
||
export type FieldErrorProps = { | ||
id?: string; | ||
text: string; | ||
}; | ||
|
||
const FieldError = ({ id, text }: FieldErrorProps) => { | ||
return ( | ||
<FormHelperText error id={id}> | ||
<ScreenReaderText>Error:</ScreenReaderText> | ||
{text} | ||
</FormHelperText> | ||
); | ||
}; | ||
|
||
const MemoizedFieldError = memo(FieldError); | ||
|
||
export { MemoizedFieldError as FieldError }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/*! | ||
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved. | ||
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") | ||
* | ||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* | ||
* See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
import { memo } from "react"; | ||
|
||
import { FormHelperText } from "./"; | ||
|
||
export type FieldHintProps = { | ||
id?: string; | ||
text: string; | ||
}; | ||
|
||
const FieldHint = ({ id, text }: FieldHintProps) => { | ||
return <FormHelperText id={id}>{text}</FormHelperText>; | ||
}; | ||
|
||
const MemoizedFieldHint = memo(FieldHint); | ||
|
||
export { MemoizedFieldHint as FieldHint }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/*! | ||
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved. | ||
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") | ||
* | ||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* | ||
* See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
import { InputLabel } from "@mui/material"; | ||
import { memo, useMemo } from "react"; | ||
|
||
import { ScreenReaderText } from "./ScreenReaderText"; | ||
import { Typography } from "."; | ||
|
||
export type FieldLabelProps = { | ||
hasVisibleLabel: boolean; | ||
id: string; | ||
inputId: string; | ||
isRequired: boolean; | ||
optionalText?: string; | ||
text: string; | ||
}; | ||
|
||
const FieldLabel = ({ | ||
hasVisibleLabel, | ||
id, | ||
inputId, | ||
isRequired, | ||
optionalText, | ||
text, | ||
}: FieldLabelProps) => { | ||
const inputLabel = useMemo( | ||
() => ( | ||
<InputLabel htmlFor={inputId} id={id}> | ||
{text} | ||
{!isRequired && ( | ||
<Typography variant="subtitle1">{optionalText}</Typography> | ||
)} | ||
</InputLabel> | ||
), | ||
[id, inputId, isRequired, optionalText, text] | ||
); | ||
|
||
return hasVisibleLabel ? ( | ||
inputLabel | ||
) : ( | ||
<ScreenReaderText>{inputLabel}</ScreenReaderText> | ||
); | ||
}; | ||
|
||
const MemoizedFieldLabel = memo(FieldLabel); | ||
|
||
export { MemoizedFieldLabel as FieldLabel }; |
Oops, something went wrong.