textarea]:h-auto',
-
- // Variants based on alignment.
- 'has-[>[data-align=inline-start]]:[&>input]:pl-4',
- 'has-[>[data-align=inline-end]]:[&>input]:pr-4',
- 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-6',
- 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-6',
-
- // Focus state.
- 'has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[2px]',
-
- // Error state.
- 'has-[[data-slot][aria-invalid=true]]:ring-destructive has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive',
-
- // Custom
- isPending && 'bg-muted pointer-events-none animate-pulse',
-
- className
- )}
- {...props}
- />
+
+ textarea]:h-auto',
+
+ // Variants based on alignment.
+ 'has-[>[data-align=inline-start]]:[&>input]:pl-4',
+ 'has-[>[data-align=inline-end]]:[&>input]:pr-4',
+ 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-6',
+ 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-6',
+
+ // Focus state.
+ 'has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[2px]',
+
+ // Error state.
+ 'has-[[data-slot][aria-invalid=true]]:ring-destructive has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive',
+
+ // Custom
+ isPending && 'bg-muted pointer-events-none animate-pulse',
+
+ className
+ )}
+ {...props}
+ />
+
)
}
const inputGroupAddonVariants = cva(
- "text-muted-foreground flex h-auto cursor-text items-center justify-center gap-4 py-3 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-8 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50",
+ "text-muted-foreground flex h-auto cursor-text items-center justify-center gap-4 py-3 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-8 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-80",
{
variants: {
align: {
@@ -87,19 +97,25 @@ function InputGroupAddon({
)
}
-const inputGroupButtonVariants = cva('text-sm shadow-none flex gap-2 items-center', {
- variants: {
- size: {
- xs: "h-12 gap-2 px-4 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-7 has-[>svg]:px-4",
- sm: 'h-16 px-5 gap-3 rounded-md has-[>svg]:px-5',
- 'icon-xs': 'size-12 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
- 'icon-sm': 'size-16 p-0 has-[>svg]:p-0',
+const inputGroupButtonVariants = cva(
+ [
+ 'text-sm shadow-none flex gap-2 items-center ring-offset-0',
+ 'group-data-[disabled=true]/input-group:pointer-events-none',
+ ],
+ {
+ variants: {
+ size: {
+ xs: "h-12 gap-2 px-4 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-7 has-[>svg]:px-4",
+ sm: 'h-16 px-5 gap-3 rounded-md has-[>svg]:px-5',
+ 'icon-xs': 'size-12 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
+ 'icon-sm': 'size-16 p-0 has-[>svg]:p-0',
+ },
+ },
+ defaultVariants: {
+ size: 'xs',
},
- },
- defaultVariants: {
- size: 'xs',
- },
-})
+ }
+)
function InputGroupButton({
className,
@@ -109,11 +125,13 @@ function InputGroupButton({
...props
}: Omit, 'size'> &
VariantProps) {
+ const ctx = useInputGroup()
return (
@@ -124,7 +142,7 @@ function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
return (
) {
)
}
-function InputGroupControl({ className, ...props }: React.ComponentProps) {
+function InputGroupControl({ className, disabled, ...props }: React.ComponentProps) {
+ const ctx = useInputGroup()
+
+ const isDisabled = ctx.disabled || disabled
+
return (
) {
- return (
-
- // TODO: Work on shadcn textarea
- //
- )
-}
-
-export {
- InputGroup,
- InputGroupAddon,
- InputGroupButton,
- InputGroupControl,
- InputGroupText,
- InputGroupTextarea,
-}
+export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupControl, InputGroupText }
diff --git a/packages/react/v2/components/primitives/toggle-group.tsx b/packages/react/v2/components/primitives/toggle-group.tsx
index d4f30696..9d9c78c2 100644
--- a/packages/react/v2/components/primitives/toggle-group.tsx
+++ b/packages/react/v2/components/primitives/toggle-group.tsx
@@ -10,7 +10,7 @@ import { toggleVariants } from './toggle'
import { cn } from '../../../src/react/utils/cn'
const ToggleGroupContext = React.createContext>({
- size: 'default',
+ size: 'md',
variant: 'default',
})
diff --git a/packages/react/v2/components/primitives/toggle.tsx b/packages/react/v2/components/primitives/toggle.tsx
index 2cc893d2..105da504 100644
--- a/packages/react/v2/components/primitives/toggle.tsx
+++ b/packages/react/v2/components/primitives/toggle.tsx
@@ -17,14 +17,14 @@ const toggleVariants = cva(
'border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground',
},
size: {
- default: 'h-18 px-4 min-w-18',
+ md: 'h-18 px-4 min-w-18',
sm: 'h-16 px-3 min-w-16',
lg: 'h-20 px-5 min-w-20',
},
},
defaultVariants: {
variant: 'default',
- size: 'default',
+ size: 'md',
},
}
)
diff --git a/packages/react/v2/components/primitives/typography.tsx b/packages/react/v2/components/primitives/typography.tsx
new file mode 100644
index 00000000..30c1520f
--- /dev/null
+++ b/packages/react/v2/components/primitives/typography.tsx
@@ -0,0 +1,57 @@
+import React from 'react'
+
+import { Slot } from '@radix-ui/react-slot'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '../../../src/react/utils/cn'
+
+type TypographyTag = 'h1' | 'h2' | 'h3' | 'h4' | 'body' | 'label' | 'caption'
+
+const nativeElementsMap: Record = {
+ h1: 'h1',
+ h2: 'h2',
+ h3: 'h3',
+ h4: 'h4',
+ body: 'p',
+ caption: 'p',
+ label: 'p',
+}
+
+const typographyVariants = cva('inline-block', {
+ variants: {
+ weight: {
+ normal: 'font-normal',
+ medium: 'font-medium',
+ semibold: 'font-semibold',
+ bold: 'font-bold',
+ },
+ type: {
+ h1: 'text-3xl',
+ h2: 'text-2xl',
+ h3: 'text-xl',
+ h4: 'text-lg',
+ body: 'text-base',
+ caption: 'text-sm',
+ label: 'text-xs',
+ },
+ },
+})
+
+interface TypographyProps
+ extends React.HTMLAttributes,
+ VariantProps {
+ type?: TypographyTag
+ asChild?: boolean
+}
+
+export const Typography = ({
+ type = 'body',
+ weight = 'normal',
+ className,
+ asChild = false,
+ ...props
+}: TypographyProps) => {
+ const Component = asChild ? Slot : nativeElementsMap[type]
+
+ return
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f3c5a8dc..4c5c954f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -171,6 +171,9 @@ importers:
'@tiptap/starter-kit':
specifier: ^2.26.3
version: 2.26.3
+ date-fns:
+ specifier: ^4.1.0
+ version: 4.1.0
next:
specifier: 15.2.2
version: 15.2.2(@babel/core@7.27.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -183,6 +186,9 @@ importers:
react:
specifier: 19.1.0
version: 19.1.0
+ react-day-picker:
+ specifier: ^9.11.1
+ version: 9.11.1(react@19.1.0)
react-dom:
specifier: 19.1.0
version: 19.1.0(react@19.1.0)
@@ -288,7 +294,7 @@ importers:
version: 15.2.2(@babel/core@7.27.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
nuqs:
specifier: ^2.4.3
- version: 2.4.3(next@15.2.2(@babel/core@7.27.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
+ version: 2.4.3(next@15.2.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
radix3:
specifier: ^1.1.2
version: 1.1.2
@@ -540,7 +546,7 @@ importers:
version: 12.11.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
nuqs:
specifier: ^2.4.3
- version: 2.4.3(next@15.2.2(@babel/core@7.27.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
+ version: 2.4.3(next@15.2.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
radix3:
specifier: ^1.1.2
version: 1.1.2
@@ -593,6 +599,9 @@ importers:
'@vitejs/plugin-react':
specifier: ^4.3.4
version: 4.4.1(vite@6.3.5(@types/node@24.0.15)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.20.3))
+ react-day-picker:
+ specifier: ^9.11.1
+ version: 9.11.1(react@19.1.0)
tsup:
specifier: ^8.5.0
version: 8.5.0(jiti@2.4.2)(postcss@8.5.3)(tsx@4.20.3)(typescript@5.8.2)
@@ -968,6 +977,9 @@ packages:
'@changesets/write@0.4.0':
resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==}
+ '@date-fns/tz@1.4.1':
+ resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==}
+
'@dnd-kit/accessibility@3.1.1':
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
peerDependencies:
@@ -3557,6 +3569,12 @@ packages:
dataloader@1.4.0:
resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==}
+ date-fns-jalali@4.1.0-0:
+ resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==}
+
+ date-fns@4.1.0:
+ resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
+
debug@4.4.1:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'}
@@ -4926,6 +4944,12 @@ packages:
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1
react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1
+ react-day-picker@9.11.1:
+ resolution: {integrity: sha512-l3ub6o8NlchqIjPKrRFUCkTUEq6KwemQlfv3XZzzwpUeGwmDJ+0u0Upmt38hJyd7D/vn2dQoOoLV/qAp0o3uUw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: '>=16.8.0'
+
react-dom@19.1.0:
resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
peerDependencies:
@@ -6444,6 +6468,8 @@ snapshots:
human-id: 4.1.1
prettier: 2.8.8
+ '@date-fns/tz@1.4.1': {}
+
'@dnd-kit/accessibility@3.1.1(react@19.1.0)':
dependencies:
react: 19.1.0
@@ -9605,6 +9631,10 @@ snapshots:
dataloader@1.4.0: {}
+ date-fns-jalali@4.1.0-0: {}
+
+ date-fns@4.1.0: {}
+
debug@4.4.1:
dependencies:
ms: 2.1.3
@@ -10682,7 +10712,7 @@ snapshots:
node-releases@2.0.19: {}
- nuqs@2.4.3(next@15.2.2(@babel/core@7.27.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0):
+ nuqs@2.4.3(next@15.2.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0):
dependencies:
mitt: 3.0.1
react: 19.1.0
@@ -11113,6 +11143,13 @@ snapshots:
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
+ react-day-picker@9.11.1(react@19.1.0):
+ dependencies:
+ '@date-fns/tz': 1.4.1
+ date-fns: 4.1.0
+ date-fns-jalali: 4.1.0-0
+ react: 19.1.0
+
react-dom@19.1.0(react@19.1.0):
dependencies:
react: 19.1.0