Skip to content

Commit

Permalink
♻️ refactor: add sticker-map (without print page)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrehadianto committed Sep 26, 2024
1 parent a55bef7 commit ba7972f
Show file tree
Hide file tree
Showing 10 changed files with 2,638 additions and 1,694 deletions.
47 changes: 47 additions & 0 deletions common/components/Field/Field.theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { type VariantProps, tv } from "tailwind-variants";

export const fieldTheme = tv({
slots: {
wrapper: "",
label: ["w-full", "text-text-em-mid", "block", "pl-1"],
message: [
"mt-2",
"flex",
"items-start",
"gap-1",
"pl-1",
"text-text-em-low",
"data-[error]:text-text-error",
],
children: [],
},
variants: {
size: {
md: {
wrapper: ["gap-2"],
label: ["text-base"],
message: ["text-sm"],
},
sm: {
wrapper: ["gap-1.5"],
label: ["text-sm"],
message: ["text-xs"],
},
},
orientation: {
horizontal: {
wrapper: ["flex", "items-center"],
children: ["flex", "flex-col", "items-center"],
},
vertical: {
wrapper: ["flex", "flex-col"],
},
},
},
defaultVariants: {
size: "md",
orientation: "vertical",
},
});

export type FieldVariants = VariantProps<typeof fieldTheme>;
61 changes: 61 additions & 0 deletions common/components/Field/Field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ComponentPropsWithoutRef, ReactNode } from "react";

import { fieldTheme, type FieldVariants } from "./Field.theme";

import { cn } from "@/common/functions";

export interface FieldProps {
label?: string;
message?: ReactNode;
error?: boolean;
}

export interface FieldFullProps
extends FieldProps,
ComponentPropsWithoutRef<"div">,
FieldVariants {
labelProps?: ComponentPropsWithoutRef<"label">;

htmlFor?: string;
}

export const Field = ({
label,
children,
message,
error,
labelProps,
size,
className,
htmlFor,
orientation,
...props
}: FieldFullProps) => {
const {
wrapper,
label: labelStyle,
message: messageStyle,
children: childrenStyle,
} = fieldTheme({ className, size, orientation });
return (
<div {...props} className={cn(wrapper(), className)}>
{label && (
<label
htmlFor={htmlFor}
{...labelProps}
className={labelStyle({ className: labelProps?.className })}
>
{label}
</label>
)}
<div className={childrenStyle()}>
{children}
{message && (
<p className={messageStyle()} data-error={error ? "" : undefined}>
{message}
</p>
)}
</div>
</div>
);
};
1 change: 1 addition & 0 deletions common/components/Field/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Field";
84 changes: 84 additions & 0 deletions common/components/Input/Input.theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { tv, type VariantProps } from "tailwind-variants";

export const inputTheme = tv({
slots: {
content: [
"w-full",
"flex",
"items-center",
"whitespace-nowrap",
"transition-all",
"text-text-em-high",
"[&_input::placeholder]:text-text-em-low",
"focus-within:border-element-primary",
"[&_textarea::placeholder]:text-text-em-low",
"focus-within:text-text-em-mid",
],
sideContent: ["text-text-em-low"],
input: [
"w-full",
"flex-1",
"bg-transparent",
"focus:outline-none", // outline-0 doesn't work for Safari
"text-text-em-high",
"caret-current",
],
},
variants: {
variant: {
default: {
content: ["bg-surface-base"],
},
elevated: {
content: ["bg-surface-base-elevated"],
},
},
size: {
md: {
content: [
"py-2",
"px-3",
"max-h-9",
"rounded-[6px]",
"gap-2",
"text-base",
],
},
sm: {
content: [
"px-2.5",
"py-1.5",
"max-h-[30px]",
"rounded-[6px]",
"gap-1.5",
"text-sm",
],
},
},
hasError: {
true: {
content: "border-text-error",
},
},
unstyled: {
true: {
content: [
"border-none",
"bg-transparent",
"text-text-em-high",
"w-fit",
"p-0",
],
input: ["text-text-em-high", "w-fit", "flex-none"],
},
},
},
defaultVariants: {
variant: "default",
size: "md",
unstyled: false,
hasError: false,
},
});

export type InputVariants = VariantProps<typeof inputTheme>;
94 changes: 94 additions & 0 deletions common/components/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { ComponentPropsWithoutRef, ReactNode, forwardRef } from "react";

import { type InputVariants, inputTheme } from "./Input.theme";

import { Field, FieldFullProps, FieldProps } from "@/common/components/Field";
import { cloneElement } from "@/common/functions";

export interface InputContentProps extends FieldProps {
// contentProps => wraps the input, left and right contents
contentProps?: ComponentPropsWithoutRef<"div">;
id: string;
placeholder?: string;
leftContent?: ReactNode;
rightContent?: ReactNode;
wrapperProps?: FieldFullProps;
}

export interface InputProps
extends Omit<ComponentPropsWithoutRef<"input">, "id" | "size">,
Omit<InputVariants, "hasError">,
InputContentProps {}

export const Input = forwardRef<HTMLInputElement, InputProps>(
(
{
className,
leftContent,
rightContent,
contentProps,
wrapperProps,
placeholder,
id,
size,
label,
error,
message,
unstyled,
variant,
...props
},
ref,
) => {
const { content, input, sideContent } = inputTheme({
hasError: error,
size,
unstyled,
variant,
});

const styledLeftContent = cloneElement({
element: leftContent,
themeStyle: sideContent,
});

const styledRightContent = cloneElement({
element: rightContent,
themeStyle: sideContent,
});

return (
<Field
{...wrapperProps}
error={error}
htmlFor={id}
label={label}
message={message}
size={size}
>
<div
{...contentProps}
className={content({
className: contentProps?.className,
})}
>
{styledLeftContent}
<input
ref={ref}
autoComplete="off"
className={input({
className,
})}
id={id}
placeholder={placeholder}
type="text"
{...props}
/>
{styledRightContent}
</div>
</Field>
);
},
);

Input.displayName = "Input";
1 change: 1 addition & 0 deletions common/components/Input/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Input";
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
"dependencies": {
"@iconify-icon/react": "^2.1.0",
"clsx": "^2.1.1",
"filepond": "^4.31.4",
"framer-motion": "^11.3.19",
"next": "14.2.5",
"react": "^18",
"react-dom": "^18",
"react-filepond": "^7.1.2",
"sass": "^1.77.8",
"tailwind-merge": "^2.4.0",
"tailwind-variants": "^0.2.1"
Expand Down
Loading

0 comments on commit ba7972f

Please sign in to comment.