admin/constants/formFieldStyles.ts
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

134 lines
4.3 KiB
TypeScript

import { cn } from '@/lib/cn'
/** Shared HeroUI field wrapper classes — Remi design system (8px radius, white surface). */
export const FIELD_WRAPPER =
'bg-surface shadow-none border border-divider hover:!border-primary-hover group-data-[focus=true]:!border-primary group-data-[focus=true]:hover:!border-primary'
/** Reserve no empty space under fields when there is no error message. */
export const FIELD_HELPER_WRAPPER = 'min-h-0 p-0'
export const FIELD_RADIUS = 'md' as const
export const DATE_PICKER_CLASSNAME = 'date-picker-input'
export type RemiFieldVariant = 'flat' | 'bordered' | 'faded' | 'underlined'
export type RemiFieldSize = 'sm' | 'md' | 'lg'
interface RemiDatePickerStyleOptions {
variant?: RemiFieldVariant
size?: RemiFieldSize
isInvalid?: boolean
/** When true, border/background live on {@link REMI_BORDERED_DATE_PICKER_WRAPPER} / underlined wrapper. */
inWrapper?: boolean
}
/** Wrapper for table filters — matches HeroUI bordered `sm` Input (`h-8`, `px-2`, `rounded-medium`). */
export const REMI_BORDERED_DATE_PICKER_WRAPPER = cn(
FIELD_WRAPPER,
'flex h-8 min-h-8 w-full items-center rounded-medium px-2',
'focus-within:!border-primary focus-within:hover:!border-primary'
)
/** Wrapper for modal filters — matches HeroUI underlined `md` Input. */
export const REMI_UNDERLINED_DATE_PICKER_WRAPPER = cn(
'flex h-10 min-h-10 w-full items-center rounded-none border-b border-divider bg-surface px-1 pb-1 shadow-none',
'hover:!border-primary-hover focus-within:!border-primary'
)
/** Inline styles for react-multi-date-picker — aligned with HeroUI Input sizes in PaginatedList. */
export function getRemiDatePickerStyles({
variant = 'bordered',
size = 'md',
isInvalid = false,
inWrapper = false,
}: RemiDatePickerStyleOptions = {}) {
const errorColor = 'var(--color-fourth)'
const neutralBorder = 'var(--color-divider)'
const height = size === 'sm' ? '32px' : size === 'lg' ? '48px' : '40px'
const horizontalPadding = size === 'sm' ? '8px' : '12px'
if (inWrapper) {
return {
width: '100%',
boxSizing: 'border-box' as const,
height: '100%',
minHeight: height,
border: 'none',
background: 'transparent',
borderRadius: '0',
color: 'var(--color-text-main)',
padding: '0',
textAlign: 'right' as const,
boxShadow: 'none',
outline: 'none',
}
}
const baseStyles = {
width: '100%',
boxSizing: 'border-box' as const,
height,
borderRadius: '8px',
color: 'var(--color-text-main)',
padding: `0 ${horizontalPadding}`,
textAlign: 'right' as const,
boxShadow: 'none',
outline: 'none',
}
switch (variant) {
case 'bordered':
return {
...baseStyles,
background: 'var(--color-surface)',
border: '1px solid',
borderColor: isInvalid ? errorColor : neutralBorder,
}
case 'faded':
return {
...baseStyles,
background: '#f4f4f5',
border: '1px solid',
borderColor: isInvalid ? errorColor : neutralBorder,
}
case 'underlined':
return {
...baseStyles,
background: 'transparent',
border: 'none',
borderBottom: `1px solid ${isInvalid ? errorColor : neutralBorder}`,
borderRadius: '0',
borderColor: isInvalid ? errorColor : neutralBorder,
}
case 'flat':
default:
return {
...baseStyles,
background: '#f4f4f5',
border: isInvalid ? `1px solid ${errorColor}` : 'none',
borderColor: isInvalid ? errorColor : '#f4f4f5',
}
}
}
/** Listbox option styling — light hover/focus, no borders. */
export const REMI_LISTBOX_ITEM_CLASSES = {
base: [
'bg-surface rounded-md border-none shadow-none outline-none',
'data-[hover=true]:border-none data-[hover=true]:bg-accent-light/50 data-[hover=true]:shadow-none',
'data-[focus=true]:border-none data-[focus=true]:bg-accent-light/50 data-[focus=true]:shadow-none',
'data-[focus-visible=true]:outline-none data-[focus-visible=true]:border-none',
'data-[selected=true]:bg-primary/10 data-[selected=true]:border-none',
].join(' '),
}
export const REMI_LISTBOX_PROPS = {
emptyContent: 'موردی یافت نشد',
itemClasses: REMI_LISTBOX_ITEM_CLASSES,
classNames: {
base: 'bg-surface',
list: 'bg-surface',
},
} as const