diff --git a/.gitignore b/.gitignore index 671ed264..1acfb481 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ tsconfig.tsbuildinfo /SpaceKitProvider /Table /TextField +/Toggle /Tooltip /typography diff --git a/src/Toggle/Toggle.story.mdx b/src/Toggle/Toggle.story.mdx new file mode 100644 index 00000000..1d87123f --- /dev/null +++ b/src/Toggle/Toggle.story.mdx @@ -0,0 +1,137 @@ +import { Toggle as ToggleComponent } from "../Toggle"; +import { ClassNames } from "@emotion/core"; +import { colors } from "../colors"; +import { + Description, + Meta, + Story, + Props, + Preview, +} from "@storybook/addon-docs/blocks"; +import { mergeProps } from "@react-aria/utils"; +import noop from "lodash/noop"; + +export function Toggle(props) { + return ( + + {({ css }) => ( + + )} + + ); +} + + + +# Toggle + + + +## Uncontrolled + +Using the `defaultSelected` props to indicate these components are uncontrolled; meaning their state is not stored externally. + + + + Deslected + + + Selected + + + Disabled Deslected + + + + Disabled Selected + + + + +## Controlled + +Pass `isSelectded` and `onChange` props to indicate these components are uncontrolled; meaning their state is not stored externally. + + + + + Deslected + + + + + Selected + + + + + Disabled Deslected + + + + + Disabled Selected + + + + +## Color + +You can customize the color of the checkbox's selected state with the `color` prop + + + + Deslected + + + + Selected + + + + + Disabled Deslected + + + + + Disabled Selected + + + + +## Focus + +Toggles will show a border when focused from keyboard navigation and not from touches or clicks. + + + + + Deslected + + + + + Selected + + + + + Disabled Deslected + + + + + Disabled Selected + + + + +## Props + + diff --git a/src/Toggle/index.tsx b/src/Toggle/index.tsx new file mode 100644 index 00000000..00fffdf5 --- /dev/null +++ b/src/Toggle/index.tsx @@ -0,0 +1,118 @@ +import React from "react"; +import { ClassNames } from "@emotion/core"; +import { getOffsetInPalette } from "../colors/utils/getOffsetInPalette"; +import { ShadedColor, colors } from "../colors"; +import { useFocusRing } from "@react-aria/focus"; +import { useSwitch } from "@react-aria/switch"; +import { useToggleState } from "@react-stately/toggle"; +import { VisuallyHidden } from "@react-aria/visually-hidden"; + +type ToggleProps = { + /** + * `className` to apply to the bounding `label` + */ + className?: string; + /** + * `style` to apply to the bounding `label` + */ + style?: React.CSSProperties; + + /** + * Color to use for the checkbox itself. The check color and the border color + * will be automatically calculated. + * + * @default colors.blue.base + */ + color?: ShadedColor; + + /** + * Force the focused styling + * + * This prop is typed as `never` so you can never legally pass it. This is + * intended only for testing because there's no other way to test a focus + * ring. The only place we're actually using this is in an `mdx` file, which + * doesn't check props with TypeScript. + * + * There's got to be a better way to do this; I just don't know what it is + * :shrug: + */ + isFocusVisible?: never; +} & Parameters[0]; + +export const Toggle: React.FC = ({ + className, + style, + color = colors.blue.base, + isFocusVisible: isFocusVisibleFromProps, + ...props +}) => { + const state = useToggleState(props); + const ref = React.useRef(null); + const { inputProps } = useSwitch(props, state, ref); + const { + isFocusVisible: isFocusVisibleFromFocusRing, + focusProps, + } = useFocusRing(props); + + const isFocusVisible = + (!props.isDisabled && isFocusVisibleFromProps) || + isFocusVisibleFromFocusRing; + + return ( + + {({ css, cx }) => ( +