Skip to content

Commit

Permalink
feat(Stepper): migrate to Tailwind
Browse files Browse the repository at this point in the history
docs: update tailwind status yaml

Update packages/orbit-components/src/Stepper/StepperStateless/index.tsx

Co-authored-by: Marco Vidal García <marco.vidal@kiwi.com>

Update packages/orbit-components/src/Stepper/StepperStateless/index.tsx

Co-authored-by: Marco Vidal García <marco.vidal@kiwi.com>
  • Loading branch information
mainframev and mvidalgarcia committed Oct 27, 2023
1 parent 357996f commit e305def
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 129 deletions.
4 changes: 2 additions & 2 deletions docs/src/data/tailwind-migration-status.yaml
Expand Up @@ -82,8 +82,8 @@ Slide: false
Slider: false
SocialButton: true
Stack: true
Stepper: false
StepperStateless: false
Stepper: true
StepperStateless: true
StopoverArrow: false
Switch: true
Tab: false
Expand Down
17 changes: 16 additions & 1 deletion packages/orbit-components/src/Stepper/Stepper.stories.tsx
Expand Up @@ -101,9 +101,24 @@ export const Playground = () => {
/>
);
};

Playground.story = {
parameters: {
info: "Here you can try Stepper component with additional functionality.",
},
};

export const VisualTest = () => {
return (
<div className="space-y-md flex flex-col">
<Stepper minValue={1} maxValue={10} defaultValue={2} />
<Stepper minValue={1} maxValue={10} defaultValue={2} active />
<Stepper minValue={1} maxValue={10} defaultValue={10} disabled />
</div>
);
};

VisualTest.story = {
parameters: {
chromatic: { disableSnapshot: false },
},
};
158 changes: 41 additions & 117 deletions packages/orbit-components/src/Stepper/StepperStateless/index.tsx
@@ -1,118 +1,33 @@
"use client";

import * as React from "react";
import styled, { css } from "styled-components";
import cx from "clsx";

import mq from "../../utils/mediaQuery";
import Minus from "../../icons/Minus";
import Plus from "../../icons/Plus";
import defaultTheme from "../../defaultTheme";
import Button from "../../primitives/ButtonPrimitive";
import ButtonPrimitive from "../../primitives/ButtonPrimitive";
import useTheme from "../../hooks/useTheme";
import { defaultFocus } from "../../utils/common";
import type { Props } from "./types";

const getMaxWidth = ({ maxWidth }) => {
const getMaxWidth = ({ maxWidth }: { maxWidth: string | number }) => {
if (typeof maxWidth === "string") return maxWidth;
return `${parseInt(maxWidth, 10)}px`;
return `${parseInt(maxWidth.toString(), 10)}px`;
};

const StyledStepper = styled.div`
display: flex;
width: 100%;
max-width: ${getMaxWidth};
flex: 1 1 auto;
`;

const iconMixin = css<{ isActive?: boolean; isDisabled?: boolean }>`
${({ theme, isActive, isDisabled }) => css`
padding: 2px;
height: 20px;
width: 20px;
background: ${isActive ? theme.orbit.paletteBlueNormal : theme.orbit.paletteCloudNormal};
border-radius: ${theme.orbit.borderRadiusCircle};
${mq.desktop(css`
height: 16px;
width: 16px;
`)};
${!isDisabled &&
css`
&:hover {
background: ${isActive
? theme.orbit.paletteBlueNormalHover
: theme.orbit.paletteCloudNormalHover};
}
&:focus,
&:active {
box-shadow: inset 0 0 0 2px
${isActive ? theme.orbit.paletteBlueLightActive : theme.orbit.paletteCloudNormalActive};
}
`};
`}
`;

const StyledMinusIcon = styled(Minus)`
${iconMixin};
`;

StyledMinusIcon.defaultProps = {
theme: defaultTheme,
};

const StyledPlusIcon = styled(Plus)`
${iconMixin};
`;

StyledPlusIcon.defaultProps = {
theme: defaultTheme,
};

const StyledStepperInput = styled.input`
${({ theme, disabled }) => css`
width: 100%;
height: 44px;
padding: 0;
border: 0;
font-size: ${theme.orbit.fontSizeTextLarge};
font-weight: ${theme.orbit.fontWeightMedium};
color: ${theme.orbit.paletteInkDark};
text-align: center;
min-width: 0;
opacity: ${disabled ? "0.5" : "1"};
background-color: ${disabled && "transparent"};
&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
&:focus {
outline: none;
}
`}
`;

StyledStepperInput.defaultProps = {
theme: defaultTheme,
};

const StyledStepperButton = styled(Button)`
&:focus {
outline: none;
${StyledMinusIcon},
${StyledPlusIcon} {
${defaultFocus}
}
}
`;

StyledStepperButton.defaultProps = {
theme: defaultTheme,
};
const stepperButtonMixin = ({ disabled, active }: { disabled: boolean; active?: boolean }) =>
cx(
"[&_svg]:p-xxxs",
"de:[&_svg]:h-icon-small de:[&_svg]:w-icon-small [&_svg]:h-icon-medium [&_svg]:w-icon-medium",
"[&_svg]:rounded-circle",
"focus:outline-0",
"[&_svg]:focus:outline-blue-normal [&_svg]:focus:outline [&_svg]:focus:outline-2",
!disabled && [
active
? "[&_svg]:bg-blue-normal hover:[&_svg]:bg-blue-normal-hover [&_svg]:active:focus:shadow-[inset_0_0_0_2px_var(--palette-blue-light-active)]"
: "[&_svg]:bg-cloud-normal hover:[&_svg]:bg-cloud-normal-hover [&_svg]:active:focus:shadow-[inset_0_0_0_2px_var(--palette-cloud-normal-active)]",
],
disabled && "[&_svg]:bg-cloud-normal",
);

const StepperStateless = ({
maxWidth = "120px",
Expand All @@ -136,11 +51,6 @@ const StepperStateless = ({
}: Props) => {
const theme = useTheme();

const commonButtonStyles = {
background: "transparent",
width: "44px",
};

const iconStyles = {
foreground: active ? theme.orbit.paletteWhite : theme.orbit.paletteInkDark,
};
Expand All @@ -151,20 +61,34 @@ const StepperStateless = ({
disabled || disabledIncrement || (typeof value === "number" && value >= +maxValue);

return (
<StyledStepper data-test={dataTest} id={id} maxWidth={maxWidth}>
<StyledStepperButton
<div
data-test={dataTest}
id={id}
className="flex w-full flex-auto"
style={{ maxWidth: getMaxWidth({ maxWidth }) }}
>
<ButtonPrimitive
className={stepperButtonMixin({ disabled: isMinusDisabled, active })}
disabled={isMinusDisabled}
iconLeft={<StyledMinusIcon size="small" isActive={active} isDisabled={isMinusDisabled} />}
iconLeft={<Minus size="small" />}
onClick={ev => {
if (onDecrement && !disabled) {
onDecrement(ev);
}
}}
title={titleDecrement}
icons={iconStyles}
{...commonButtonStyles}
/>
<StyledStepperInput
<input
className={cx(
"h-form-box-normal w-full min-w-0 border-0",
"p-0 text-center",
"text-large text-form-element-filled-foreground font-medium",
"[&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
"[&::-webkit-inner-spin-button]:m-0 [&::-webkit-outer-spin-button]:m-0",
disabled ? "bg-transparent opacity-50" : "opacity-100",
"focus:outline-0",
)}
name={name}
disabled={disabled}
type="text"
Expand All @@ -180,19 +104,19 @@ const StepperStateless = ({
onFocus={onFocus}
readOnly
/>
<StyledStepperButton
<ButtonPrimitive
className={stepperButtonMixin({ disabled: isPlusDisabled, active })}
disabled={isPlusDisabled}
iconLeft={<StyledPlusIcon size="small" isActive={active} isDisabled={isPlusDisabled} />}
iconLeft={<Plus size="small" />}
onClick={ev => {
if (onIncrement && !disabled) {
onIncrement(ev);
}
}}
title={titleIncrement}
icons={iconStyles}
{...commonButtonStyles}
/>
</StyledStepper>
</div>
);
};

Expand Down
Expand Up @@ -2,7 +2,6 @@ import * as React from "react";
import userEvent from "@testing-library/user-event";

import { render, screen, fireEvent } from "../../test-utils";
import defaultTheme from "../../defaultTheme";
import StepperStateless from "../StepperStateless";

describe("Stepper", () => {
Expand Down Expand Up @@ -57,14 +56,6 @@ describe("Stepper", () => {
expect(onBlur).toHaveBeenCalled();
});

it("should have active state", () => {
render(<StepperStateless value="kek" active />);

expect(document.querySelector("svg")).toHaveStyle({
background: defaultTheme.orbit.paletteBlueNormal,
});
});

it("should have maxWidth", () => {
render(<StepperStateless value="kek" dataTest="kek" maxWidth={200} />);

Expand Down

0 comments on commit e305def

Please sign in to comment.