diff --git a/.changeset/frank-wings-strive.md b/.changeset/frank-wings-strive.md new file mode 100644 index 00000000..bcfafa7e --- /dev/null +++ b/.changeset/frank-wings-strive.md @@ -0,0 +1,5 @@ +--- +"@shipfox/react-ui": minor +--- + +Add checkbox and label components diff --git a/libs/react/ui/index.css b/libs/react/ui/index.css index 87004cb6..e992d928 100644 --- a/libs/react/ui/index.css +++ b/libs/react/ui/index.css @@ -321,6 +321,36 @@ --shadow-button-danger-focus: 0 -1px 0 0 var(--color-alpha-white-16), 0 0 0 1px var(--color-alpha-white-12), 0 0 0 1px var(--color-red-700), 0 0 0 2px var(--color-alpha-white-88), 0 0 0 4px var(--color-primary-500); + + /* Checkbox */ + /* Checkbox - Unchecked States */ + --checkbox-unchecked-bg: var(--background-components-base); + --checkbox-unchecked-bg-hover: var(--background-components-hover); + --checkbox-unchecked-border: var(--color-alpha-black-8); + --checkbox-unchecked-shadow: + 0px 1px 2px 0px var(--color-alpha-black-12), 0px 0px 0px 1px var(--color-alpha-black-8); + --checkbox-unchecked-focus-shadow: + 0px 1px 2px 0px rgba(30, 58, 138, 0.5), 0px 0px 0px 1px #ff4b00, 0px 0px 0px 2px + var(--color-neutral-0), 0px 0px 0px 4px rgba(255, 75, 0, 0.6); + + /* Checkbox - Checked States */ + --checkbox-checked-bg: var(--foreground-highlight-interactive); + --checkbox-checked-bg-hover: var(--foreground-highlight-interactive-hover); + --checkbox-checked-border: rgba(255, 75, 0, 0.69); + --checkbox-checked-shadow: + 0px 1px 2px 0px rgba(30, 58, 138, 0.5), 0px 0px 0px 1px rgba(255, 75, 0, 0.69); + --checkbox-checked-focus-shadow: + 0px 1px 2px 0px rgba(30, 58, 138, 0.5), 0px 0px 0px 1px #ff4b00, 0px 0px 0px 2px + var(--color-neutral-0), 0px 0px 0px 4px rgba(255, 75, 0, 0.6); + + /* Checkbox - Indeterminate States */ + --checkbox-indeterminate-bg: var(--foreground-highlight-interactive); + --checkbox-indeterminate-bg-hover: var(--foreground-highlight-interactive-hover); + --checkbox-indeterminate-border: rgba(255, 75, 0, 0.69); + --checkbox-indeterminate-shadow: + 0px 1px 2px 0px rgba(30, 58, 138, 0.5), 0px 0px 0px 1px rgba(255, 75, 0, 0.69); + --checkbox-indeterminate-focus-shadow: + 0px 0px 0px 1px var(--color-neutral-0), 0px 0px 0px 3px rgba(255, 75, 0, 0.6); --shadow-tooltip: 0 0 0 1px var(--color-alpha-black-8), 0 2px 4px 0 var(--color-alpha-black-8), 0 4px 8px 0 var(--color-alpha-black-8); @@ -482,6 +512,40 @@ --shadow-button-danger-focus: 0 -1px 0 0 var(--color-alpha-white-16), 0 0 0 1px var(--color-alpha-white-12), 0 0 0 1px var(--color-red-700), 0 0 0 2px var(--color-neutral-950), 0 0 0 4px var(--color-primary-500); + + /* Checkbox */ + /* Checkbox - Unchecked States */ + --checkbox-unchecked-bg: var(--background-components-base); + --checkbox-unchecked-bg-hover: var(--background-components-hover); + --checkbox-unchecked-border: var(--color-alpha-white-10); + --checkbox-unchecked-shadow: + 0px 1px 2px 0px var(--color-alpha-black-12), 0px 0px 0px 1px var(--color-alpha-white-10); + --checkbox-unchecked-focus-shadow: + 0px 1px 2px 0px rgba(30, 58, 138, 0.5), 0px 0px 0px 1px #ff4b00, 0px 0px 0px 2px var( + --color-alpha-black-80 + ), + 0px 0px 0px 4px rgba(255, 75, 0, 0.6); + + /* Checkbox - Checked States */ + --checkbox-checked-bg: var(--foreground-highlight-interactive); + --checkbox-checked-bg-hover: var(--foreground-highlight-interactive-hover); + --checkbox-checked-border: rgba(255, 75, 0, 0.69); + --checkbox-checked-shadow: + 0px 1px 2px 0px rgba(30, 58, 138, 0.5), 0px 0px 0px 1px rgba(255, 75, 0, 0.69); + --checkbox-checked-focus-shadow: + 0px 1px 2px 0px rgba(30, 58, 138, 0.5), 0px 0px 0px 1px #ff4b00, 0px 0px 0px 2px var( + --color-alpha-black-80 + ), + 0px 0px 0px 4px rgba(255, 75, 0, 0.6); + + /* Checkbox - Indeterminate States */ + --checkbox-indeterminate-bg: var(--foreground-highlight-interactive); + --checkbox-indeterminate-bg-hover: var(--foreground-highlight-interactive-hover); + --checkbox-indeterminate-border: rgba(255, 75, 0, 0.69); + --checkbox-indeterminate-shadow: + 0px 1px 2px 0px rgba(30, 58, 138, 0.5), 0px 0px 0px 1px rgba(255, 75, 0, 0.69); + --checkbox-indeterminate-focus-shadow: + 0px 0px 0px 1px var(--color-alpha-black-80), 0px 0px 0px 3px rgba(255, 75, 0, 0.6); --shadow-tooltip: 0 -1px 0 0 var(--color-alpha-white-4), 0 2px 4px 0 var(--color-alpha-black-40), 0 0 0 1px var(--color-alpha-white-10), 0 4px 8px 0 var(--color-alpha-black-40); @@ -808,6 +872,23 @@ --shadow-button-neutral-focus: var(--shadow-button-neutral-focus); --shadow-button-danger: var(--shadow-button-danger); --shadow-button-danger-focus: var(--shadow-button-danger-focus); + + /* Checkbox */ + --color-checkbox-unchecked-bg: var(--checkbox-unchecked-bg); + --color-checkbox-unchecked-bg-hover: var(--checkbox-unchecked-bg-hover); + --color-checkbox-unchecked-border: var(--checkbox-unchecked-border); + --shadow-checkbox-unchecked: var(--checkbox-unchecked-shadow); + --shadow-checkbox-unchecked-focus: var(--checkbox-unchecked-focus-shadow); + --color-checkbox-checked-bg: var(--checkbox-checked-bg); + --color-checkbox-checked-bg-hover: var(--checkbox-checked-bg-hover); + --color-checkbox-checked-border: var(--checkbox-checked-border); + --shadow-checkbox-checked: var(--checkbox-checked-shadow); + --shadow-checkbox-checked-focus: var(--checkbox-checked-focus-shadow); + --color-checkbox-indeterminate-bg: var(--checkbox-indeterminate-bg); + --color-checkbox-indeterminate-bg-hover: var(--checkbox-indeterminate-bg-hover); + --color-checkbox-indeterminate-border: var(--checkbox-indeterminate-border); + --shadow-checkbox-indeterminate: var(--checkbox-indeterminate-shadow); + --shadow-checkbox-indeterminate-focus: var(--checkbox-indeterminate-focus-shadow); --shadow-tooltip: var(--shadow-tooltip); } diff --git a/libs/react/ui/src/components/checkbox/checkbox-label.tsx b/libs/react/ui/src/components/checkbox/checkbox-label.tsx new file mode 100644 index 00000000..437fa4a9 --- /dev/null +++ b/libs/react/ui/src/components/checkbox/checkbox-label.tsx @@ -0,0 +1,125 @@ +import {useId} from 'react'; +import {cn} from 'utils/cn'; +import {Icon} from '../icon/icon'; +import {Label} from '../label/label'; +import {Checkbox, type CheckboxProps} from './checkbox'; + +export type CheckboxLabelProps = Omit & { + id?: string; + label: string; + optional?: boolean; + description?: string; + showInfoIcon?: boolean; + border?: boolean; + className?: string; + labelClassName?: string; + descriptionClassName?: string; +}; + +export function CheckboxLabel({ + id, + label, + optional = false, + description, + showInfoIcon = false, + border = false, + className, + labelClassName, + descriptionClassName, + ...checkboxProps +}: CheckboxLabelProps) { + const generateId = useId(); + const checkboxId = id || generateId; + const isDisabled = checkboxProps.disabled ?? false; + + const renderContent = (checkboxId: string) => ( +
+
+ + {optional && ( + + (Optional) + + )} + {showInfoIcon && ( +
+ {description && ( +

+ {description} +

+ )} +
+ ); + + if (border) { + return ( + + ); + } + + // Without border variant + return ( +
+ + + + {renderContent(checkboxId)} +
+ ); +} diff --git a/libs/react/ui/src/components/checkbox/checkbox-links.tsx b/libs/react/ui/src/components/checkbox/checkbox-links.tsx new file mode 100644 index 00000000..5218f488 --- /dev/null +++ b/libs/react/ui/src/components/checkbox/checkbox-links.tsx @@ -0,0 +1,90 @@ +import {Label} from 'components/label'; +import {type ReactNode, useId} from 'react'; +import {cn} from 'utils/cn'; +import {Checkbox, type CheckboxProps} from './checkbox'; + +export type CheckboxLink = { + label: string; + href?: string; + onClick?: () => void; +}; + +export type CheckboxLinksProps = Omit & { + id?: string; + label: string; + links: CheckboxLink[]; + separator?: ReactNode; + className?: string; + labelClassName?: string; + linkClassName?: string; +}; + +export function CheckboxLinks({ + id, + label, + links, + separator, + className, + labelClassName, + linkClassName, + ...checkboxProps +}: CheckboxLinksProps) { + const generateId = useId(); + const checkboxId = id || generateId; + const isDisabled = checkboxProps.disabled ?? false; + const defaultSeparator = ( +