diff --git a/src/OutlinedField.tsx b/src/FieldContainer.tsx similarity index 59% rename from src/OutlinedField.tsx rename to src/FieldContainer.tsx index 42315f2..5af30c3 100644 --- a/src/OutlinedField.tsx +++ b/src/FieldContainer.tsx @@ -2,27 +2,33 @@ import type React from "react"; import { makeStyles } from "tss-react/mui"; import { Z_INDEXES, getUtilityClasses } from "./styles"; -export type OutlinedFieldClasses = ReturnType["classes"]; +export type FieldContainerClasses = ReturnType["classes"]; -export type OutlinedFieldProps = { - /** The content to render inside the outline. */ +export type FieldContainerProps = { + /** + * Which style to use for the field. "outlined" shows a border around the children, + * which updates its appearance depending on hover/focus states, like MUI's + * OutlinedInput. "standard" does not include any outer border. + */ + variant?: "outlined" | "standard"; + /** The content to render inside the container. */ children: React.ReactNode; /** Class applied to the `root` element. */ className?: string; /** Override or extend existing styles. */ - classes?: Partial; + classes?: Partial; focused?: boolean; disabled?: boolean; }; -const outlinedFieldClasses: OutlinedFieldClasses = getUtilityClasses( - OutlinedField.name, - ["root", "focused", "disabled", "notchedOutline"] +const fieldContainerClasses: FieldContainerClasses = getUtilityClasses( + FieldContainer.name, + ["root", "outlined", "standard", "focused", "disabled", "notchedOutline"] ); // eslint-disable-next-line @typescript-eslint/no-invalid-void-type const useStyles = makeStyles({ - name: { OutlinedField }, + name: { FieldContainer }, uniqId: "Os7ZPW", // https://docs.tss-react.dev/nested-selectors#ssr })((theme, _params, classes) => { // Based on the concept behind and styles of OutlinedInput and NotchedOutline @@ -30,7 +36,9 @@ const useStyles = makeStyles({ // https://github.com/mui-org/material-ui/blob/a4972c5931e637611f6421ed2a5cc3f78207cbb2/packages/material-ui/src/OutlinedInput/OutlinedInput.js#L9-L37 // https://github.com/mui/material-ui/blob/a4972c5931e637611f6421ed2a5cc3f78207cbb2/packages/material-ui/src/OutlinedInput/NotchedOutline.js return { - root: { + root: {}, + + outlined: { borderRadius: theme.shape.borderRadius, padding: 1, // position: "relative", @@ -40,7 +48,10 @@ const useStyles = makeStyles({ }, }, - // Styles applied to the root element if the component is focused. + standard: {}, + + // Styles applied to the root element if the component is focused (if the + // `focused` prop is true). focused: { // Use && to trump &:hover above [`&& .${classes.notchedOutline}`]: { @@ -49,7 +60,8 @@ const useStyles = makeStyles({ }, }, - // Styles applied to the root element if the component is disabled. + // Styles applied to the root element if the component is disabled (if the + // `disabled` prop is true) disabled: { // Use && to trump &:hover above [`&& .${classes.notchedOutline}`]: { @@ -74,14 +86,19 @@ const useStyles = makeStyles({ }; }); -/** A component used to show an outline around a given field/input child. */ -export default function OutlinedField({ +/** + * Renders an element with classes and styles that correspond to the state and + * style-variant of a user-input field, the content of which should be passed in as + * `children`. + */ +export default function FieldContainer({ + variant, children, focused, disabled, classes: overrideClasses = {}, className, -}: OutlinedFieldProps) { +}: FieldContainerProps) { const { classes, cx } = useStyles(undefined, { props: { classes: overrideClasses }, }); @@ -89,21 +106,27 @@ export default function OutlinedField({ return (
{children} -
+ + {variant === "outlined" && ( +
+ )}
); } diff --git a/src/RichTextField.tsx b/src/RichTextField.tsx index e554680..486fb0f 100644 --- a/src/RichTextField.tsx +++ b/src/RichTextField.tsx @@ -1,6 +1,6 @@ import { makeStyles } from "tss-react/mui"; +import FieldContainer from "./FieldContainer"; import MenuBar, { type MenuBarProps } from "./MenuBar"; -import OutlinedField from "./OutlinedField"; import RichTextContent, { type RichTextContentProps } from "./RichTextContent"; import { useRichTextEditorContext } from "./context"; import useDebouncedFocus from "./hooks/useDebouncedFocus"; @@ -10,7 +10,11 @@ import DebounceRender from "./utils/DebounceRender"; export type RichTextFieldClasses = ReturnType["classes"]; export type RichTextFieldProps = { - /** Which style to use for */ + /** + * Which style to use for the field. "outlined" shows a border around the controls, + * editor, and footer, which updates depending on hover/focus states, like MUI's + * OutlinedInput. "standard" does not include any outer border. + */ variant?: "outlined" | "standard"; /** Class applied to the root element. */ className?: string; @@ -119,14 +123,25 @@ export default function RichTextField({ }); const editor = useRichTextEditorContext(); - // Because the user interactions with the editor menu bar buttons unfocus the - // editor (since it's not part of the editor content), we'll debounce our - // visual focused state of the OutlinedField so that it doesn't "flash" when - // that happens - const isOutlinedFieldFocused = useDebouncedFocus({ editor }); + // Because the user interactions with the editor menu bar buttons unfocus the editor + // (since it's not part of the editor content), we'll debounce our visual focused + // state so that the (outlined) field focus styles don't "flash" whenever that happens + const isFieldFocused = useDebouncedFocus({ editor }); - const content = ( - <> + return ( + {controls && ( {footer} - - ); - - return variant === "outlined" ? ( - - {content} - - ) : ( -
- {content} -
+
); } diff --git a/src/hooks/useDebouncedFocus.ts b/src/hooks/useDebouncedFocus.ts index 7faf08d..4421811 100644 --- a/src/hooks/useDebouncedFocus.ts +++ b/src/hooks/useDebouncedFocus.ts @@ -16,7 +16,7 @@ export type UseDebouncedFocusOptions = { * menu bar buttons. * * This is useful for showing the focus state visually, as with the `focused` - * prop of . + * prop of . */ export default function useDebouncedFocus({ editor, diff --git a/src/styles.ts b/src/styles.ts index 95875bb..3a02876 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -15,8 +15,8 @@ export const Z_INDEXES = { // The menu bar must sit higher than the table components (like the // column-resize-handle and selectedCells) of the editor. MENU_BAR: 2, - // The notched outline of the OutlinedField should be at the same z-index as - // the menu-bar, so that it can contain/enclose it + // The notched outline of the "outlined" field variant should be at the same z-index + // as the menu-bar, so that it can contain/enclose it NOTCHED_OUTLINE: 2, // The bubble menus should appear on top of the menu bar BUBBLE_MENU: 3,