Skip to content

Commit

Permalink
refactor(checkbox): ♻️ label with focus & hover (#188)
Browse files Browse the repository at this point in the history
  • Loading branch information
navin-moorthy authored Oct 25, 2021
1 parent 3e033ec commit bc4e4ad
Show file tree
Hide file tree
Showing 14 changed files with 388 additions and 331 deletions.
3 changes: 2 additions & 1 deletion .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
features: { previewCsfV3: true },
framework: "@storybook/react",
features: { storyStoreV7: true, babelModeV7: true },
stories: ["../src/*/stories/*.stories.@(ts|tsx)"],
addons: [
"storybook-addon-preview",
Expand Down
29 changes: 29 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,35 @@ module.exports = function (api) {
["@babel/plugin-proposal-logical-assignment-operators", { loose: true }],
["@babel/plugin-proposal-private-property-in-object", { loose: true }],
["@babel/plugin-proposal-private-methods", { loose: true }],
"@babel/plugin-transform-shorthand-properties",
"@babel/plugin-transform-block-scoping",
["@babel/plugin-proposal-decorators", { legacy: true }],
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-syntax-dynamic-import",
[
"@babel/plugin-proposal-object-rest-spread",
{
loose: true,
useBuiltIns: true,
},
],
"@babel/plugin-transform-classes",
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-parameters",
"@babel/plugin-transform-destructuring",
"@babel/plugin-transform-spread",
"@babel/plugin-transform-for-of",
"babel-plugin-macros",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-nullish-coalescing-operator",
[
"babel-plugin-polyfill-corejs3",
{
method: "usage-global",
absoluteImports: "core-js",
version: "3.18.3",
},
],
isBuild
? [
"babel-plugin-jsx-remove-data-test-id",
Expand Down
1 change: 0 additions & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@ export default {
},
coveragePathIgnorePatterns: ["node_modules", "__mocks__", "stories"],
clearMocks: true,
transformIgnorePatterns: ["<rootDir>/node_modules/(?!lodash-es)"],
};
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@
"@commitlint/config-conventional": "13.2.0",
"@release-it/conventional-changelog": "3.3.0",
"@size-limit/preset-big-lib": "5.0.5",
"@storybook/addon-a11y": "6.4.0-beta.18",
"@storybook/addon-actions": "6.4.0-beta.18",
"@storybook/addon-essentials": "6.4.0-beta.18",
"@storybook/addon-a11y": "6.4.0-beta.19",
"@storybook/addon-actions": "6.4.0-beta.19",
"@storybook/addon-essentials": "6.4.0-beta.19",
"@storybook/addon-postcss": "2.0.0",
"@storybook/react": "6.4.0-beta.18",
"@storybook/react": "6.4.0-beta.19",
"@testing-library/dom": "8.10.1",
"@testing-library/jest-dom": "5.14.1",
"@testing-library/react": "12.1.2",
Expand Down
11 changes: 5 additions & 6 deletions src/checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,12 @@ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
<CheckboxLabel {...labelProps}>
<CheckboxInput ref={ref} {...inputProps} />
<CheckboxIcon {...iconProps} />
{label && !description ? <CheckboxText {...textProps} /> : null}
{label && description ? (
<div>
<CheckboxText {...textProps} />
<div>
{label ? <CheckboxText {...textProps} /> : null}
{label && description ? (
<CheckboxDescription {...descriptionProps} />
</div>
) : null}
) : null}
</div>
</CheckboxLabel>
);
},
Expand Down
7 changes: 6 additions & 1 deletion src/checkbox/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from "react";

import { getComponentProps, RenderProp } from "../utils";
import { getComponentProps, RenderProp, runIfFnChildren } from "../utils";

import {
CheckboxGroupInitialState,
Expand Down Expand Up @@ -45,6 +45,11 @@ export const CheckboxGroup = React.forwardRef<
finalChildren.length <= state.maxVisibleItems
? null
: finalChildren.slice(state.maxVisibleItems);
console.log(
"%cmoreChildren",
"color: #0088cc",
runIfFnChildren(moreChildren),
);

return (
<RenderlesskitCheckboxGroup ref={ref} {...state} {...restProps}>
Expand Down
21 changes: 15 additions & 6 deletions src/checkbox/CheckboxIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type CheckboxIconOptions = BoxOptions &
CheckboxStateReturn,
"isChecked" | "isIndeterminate" | "isUnchecked" | "size"
> & {
label?: CheckboxProps["label"];
description?: CheckboxProps["description"];
};

Expand All @@ -29,21 +30,27 @@ export const useCheckboxIcon = createHook<
keys: CHECKBOX_ICON_KEYS,

useProps(options, htmlProps) {
const { isChecked, isIndeterminate, isUnchecked, size, description } =
options;
const {
isChecked,
isIndeterminate,
isUnchecked,
size,
label,
description,
} = options;
console.log("%clabel", "color: #00bf00", label);
const { className: htmlClassName, ...restHtmlProps } = htmlProps;

const theme = useTheme("checkbox");
const className = cx(
theme.icon.base,
description ? theme.icon.description : "",
theme.icon.size[size],
isUnchecked
? cx(
theme.icon.unChecked.default,
theme.icon.unChecked.hover,
theme.icon.unChecked.active,
theme.icon.unChecked.focus,
!label || (label && description) ? theme.icon.unChecked.focus : "",
theme.icon.unChecked.disabled,
)
: "",
Expand All @@ -52,7 +59,7 @@ export const useCheckboxIcon = createHook<
theme.icon.checked.default,
theme.icon.checked.hover,
theme.icon.checked.active,
theme.icon.checked.focus,
!label || (label && description) ? theme.icon.checked.focus : "",
theme.icon.checked.disabled,
)
: "",
Expand All @@ -61,7 +68,9 @@ export const useCheckboxIcon = createHook<
theme.icon.checked.default,
theme.icon.indeterminate.hover,
theme.icon.indeterminate.active,
theme.icon.indeterminate.focus,
!label || (label && description)
? theme.icon.indeterminate.focus
: "",
theme.icon.indeterminate.disabled,
)
: "",
Expand Down
8 changes: 5 additions & 3 deletions src/checkbox/CheckboxLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { CheckboxStateReturn } from "./CheckboxState";

export type CheckboxLabelOptions = BoxOptions &
Pick<CheckboxStateReturn, "size" | "maxVisibleItems" | "stack"> & {
label?: CheckboxProps["label"];
description?: CheckboxProps["description"];
disabled?: CheckboxProps["disabled"];
};
Expand All @@ -27,14 +28,15 @@ export const useCheckboxLabel = createHook<
keys: CHECKBOX_LABEL_KEYS,

useProps(options, htmlProps) {
const { size, disabled, description, maxVisibleItems, stack } = options;
const { size, disabled, label, description, maxVisibleItems, stack } =
options;
const { className: htmlClassName, ...restHtmlProps } = htmlProps;

const theme = useTheme("checkbox");
const className = cx(
theme.label.base,
!description ? theme.label.size[size] : "",
!description ? (disabled ? "" : theme.label.only) : "",
label && !description ? theme.label.size[size] : "",
label && !description ? (disabled ? "" : theme.label.only) : "",
disabled ? theme.label.disabled : "",
maxVisibleItems != null ? theme.label.showMore[stack] : "",
htmlClassName,
Expand Down
2 changes: 2 additions & 0 deletions src/checkbox/CheckboxState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export const useCheckboxProps = (
...state,
className,
style,
label: _label,
description: _description,
disabled: restProps.disabled,
...componentProps.labelProps,
Expand All @@ -159,6 +160,7 @@ export const useCheckboxProps = (

const iconProps: CheckboxIconProps = {
...state,
label: _label,
description: _description,
...componentProps.iconProps,
children: runIfFn(_icon, state),
Expand Down
1 change: 1 addition & 0 deletions src/checkbox/__keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const USE_CHECKBOX_STATE_KEYS = [
export const CHECKBOX_DESCRIPTION_KEYS = CHECKBOX_STATE_KEYS;
export const CHECKBOX_ICON_KEYS = [
...CHECKBOX_DESCRIPTION_KEYS,
"label",
"description",
] as const;
export const CHECKBOX_INPUT_KEYS = CHECKBOX_DESCRIPTION_KEYS;
Expand Down
12 changes: 11 additions & 1 deletion src/checkbox/stories/CheckboxBasic.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,17 @@ export const Indeterminate: Story = {

export const Label: Story = {
...Default,
args: { ...Default.args, label: "Checkbox" },
args: { ...Default.args, label: "Checkboxs" },
};

export const MultilineLabel: Story = {
...Default,
args: {
...Default.args,
label:
"Used when the checkbox is selected and will use its value for the form submission.",
className: "w-72",
},
};

export const Description: Story = {
Expand Down
11 changes: 5 additions & 6 deletions src/theme/defaultTheme/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,19 @@ export const checkbox = {
},
},
label: {
base: "relative inline-flex items-center cursor-pointer align-top",
only: "hover:bg-gray-100",
base: "relative inline-flex cursor-pointer align-top",
only: "hover:bg-gray-100 focus-within:ring-2 focus-within:ring-gray-300",
disabled: "pointer-events-none",
size: {
sm: "min-h-[26px] px-2 pb-px rounded-lg",
md: "min-h-[30px] px-2.5 rounded-lg",
lg: "min-h-11 px-4 rounded-xl",
sm: "min-h-[26px] px-2 py-[6px] rounded-lg",
md: "min-h-[30px] px-2.5 py-[7px] rounded-lg",
lg: "min-h-9 px-3 py-2 rounded-[10px]",
},
showMore: { vertical: "flex w-full", horizontal: "flex" },
},
input: "peer sr-only",
icon: {
base: "inline-flex items-center justify-center flex-shrink-0 align-top select-none transition-all",
description: "self-start",
size: {
sm: "w-3.5 h-3.5 text-[10px] border-[1.5px] rounded",
md: "w-4 h-4 text-xs border-[1.5px] rounded",
Expand Down
12 changes: 6 additions & 6 deletions src/utils/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ export function getValidChildren(children: React.ReactNode) {
}

// Merge library & user prop
export const passProps = (icon: RenderPropType, props?: Dict) => {
return React.isValidElement(icon)
? React.cloneElement(icon, {
export const passProps = (component: RenderPropType, props?: Dict) => {
return React.isValidElement(component)
? React.cloneElement(component, {
...props,
...icon.props,
className: cx(props?.className, icon.props.className),
...component.props,
className: cx(props?.className, component.props.className),
})
: runIfFn(icon, { ...props });
: runIfFn(component, { ...props });
};

// Add a11y to the icon passed
Expand Down
Loading

1 comment on commit bc4e4ad

@vercel
Copy link

@vercel vercel bot commented on bc4e4ad Oct 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.