chore(ts-migration): migrate UI primitives and design system to TypeScript
Phase 6. 57 files: 23 vendored shadcn primitives, 30 design-system components,
4 charts. Plus `src/components/ds/props.ts`, which is types only.
Renaming these alone took typecheck from 37 to 1008, and the reason is worth
recording because it is the shape of every remaining phase.
These components had NO prop contract. No PropTypes, no validation: in the
JavaScript every prop was optional and every extra prop was spread onto the
underlying element. TypeScript infers a destructured parameter WITHOUT a default
as REQUIRED, so the moment the files became `.tsx` it invented a rule the
components never had and rejected several hundred call sites that have always
worked. That is the compiler describing its own inference, not a defect it
found.
Three mechanical fixes, each restoring a contract that already existed:
- 57 JSDoc `@type {React.ForwardRefExoticComponent<any>}` annotations become
real TypeScript annotations. Those comments were the previous authors'
deliberate compatibility types; JSDoc stops applying in a `.tsx` file, so
converting them preserves an intent that was already written down.
- 61 `React.forwardRef(...)` calls gain `<any, any>`. Without generics `ref`
infers `ForwardedRef<unknown>`, which no element's `Ref<T>` accepts - so
every primitive that forwards a ref to a `div` failed on the ref, not the
props.
- 78 component signatures take `DsProps`, a documented alias for
`Record<string, any>`. It exists so the decision is recorded once and is
greppable when someone tightens it, rather than being 78 bare `any`s with
no explanation between them. The prop NAMES are not lost: every component
still destructures them by name, which is where a reader looks.
Four files needed real types rather than compatibility ones. `ds/toast` takes
react-hot-toast's own `ToastOptions`, which narrows `position` to its
`ToastPosition` union instead of widening to `string` - the widening was what
made all six calls unassignable. `ds/Pagination`'s page range is genuinely
`(number | string)[]`, because it interleaves page numbers with '…' markers that
the renderer tests for. `ds/Field` narrows `children.props` at three reads, and
`ds/Avatar` needed the ref generic.
Two of my own automated passes were wrong and were caught rather than shipped. A
props-interface generator dropped alternating props, because non-overlapping
regex matches consume the separating comma - it made things worse (83 file
errors to 146) and was reverted wholesale. A second pass missed every
multi-line signature whose defaults contain a `)`, such as `onClose = () => {}`;
that needed a brace matcher rather than a character class.
56 of 57 files emit byte-identical JavaScript. The one exception is `ds/toast`,
where a JSDoc type CAST - `/** @type {ToastPosition} */ ('bottom-center')` -
became a real annotation, so the emitted output loses a comment and a pair of
now-redundant parentheses. The value is `"bottom-center"` either way; the
minified outputs differ only in esbuild's choice of mangled local names.
Verified: tsc 37 -> 35, set-difference showing zero introduced and two removed;
zero errors remain in any Phase 6 file; npm test 1684/1691 with the same seven
failures; lint 0 errors; build succeeds with the API origin inlined; baseline
artifacts untouched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from '@/components/ds/props';
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
@@ -104,7 +105,7 @@ function getDeptColor(index, avgScore) {
|
||||
}
|
||||
|
||||
/** @param {any} props */
|
||||
export function DepartmentPerformance({ items = [], className = '' }) {
|
||||
export function DepartmentPerformance({ items = [], className = '' }: DsProps) {
|
||||
const [viewMode, setViewMode] = useState('flowchart'); // 'flowchart' | 'table'
|
||||
const [activeDept, setActiveDept] = useState(null);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from '@/components/ds/props';
|
||||
import React from 'react';
|
||||
import { BarChart } from '@mui/x-charts';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
@@ -19,7 +20,7 @@ import { chartSx, TONES, tooltipSx } from './muiChartTheme';
|
||||
* component derives no figures of its own.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function HiringFlow({ stages = [], transitions = [], weakestKey, className = '' }) {
|
||||
export function HiringFlow({ stages = [], transitions = [], weakestKey, className = '' }: DsProps) {
|
||||
if (!stages.length) return null;
|
||||
|
||||
const total = stages[0]?.count || 1;
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from '@/components/ds/props';
|
||||
import React from 'react';
|
||||
import { LineChart } from '@mui/x-charts';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -15,7 +16,7 @@ import { chartSx, TONES, tooltipSx } from './muiChartTheme';
|
||||
* `points: [{ label, hires, cumulative }]` — supplied by the page.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function HiringTrendChart({ points = [], emptyState, className = '' }) {
|
||||
export function HiringTrendChart({ points = [], emptyState, className = '' }: DsProps) {
|
||||
const enough = points.length >= 2;
|
||||
|
||||
return (
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Avatar } from '@/components/ds/Avatar';
|
||||
@@ -30,7 +31,7 @@ export function ActivityCard({
|
||||
variant = 'row',
|
||||
onClick,
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const iconTones = {
|
||||
soft: 'bg-krow-blue-tint text-krow-blue',
|
||||
brand: 'bg-krow-blue text-white',
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { AlertCircle, CheckCircle2, Info, TriangleAlert, X } from 'lucide-react';
|
||||
import { cva } from 'class-variance-authority';
|
||||
@@ -40,7 +41,7 @@ const ICON_COLORS = {
|
||||
* that persists is noise.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function Alert({ tone = 'info', title, children, icon, onDismiss, action, className, ...props }) {
|
||||
export function Alert({ tone = 'info', title, children, icon, onDismiss, action, className, ...props }: DsProps) {
|
||||
const Icon = icon || ICONS[tone];
|
||||
|
||||
return (
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -41,8 +42,7 @@ export function initialsFrom(name = '') {
|
||||
* first-class state rather than a fallback afterthought. A failed image load
|
||||
* degrades to initials instead of a broken-image icon.
|
||||
*/
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
export const Avatar = React.forwardRef(
|
||||
export const Avatar: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(
|
||||
({ name, src, size = 'default', shape, tone, status, className, ...props }, ref) => {
|
||||
const [failed, setFailed] = React.useState(false);
|
||||
const showImage = src && !failed;
|
||||
@@ -91,7 +91,7 @@ Avatar.displayName = 'Avatar';
|
||||
* people in a tight row (applicants on a position, endorsers on a skill).
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function AvatarGroup({ people = [], max = 4, size = 'sm', className }) {
|
||||
export function AvatarGroup({ people = [], max = 4, size = 'sm', className }: DsProps) {
|
||||
const visible = people.slice(0, max);
|
||||
const overflow = people.length - visible.length;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { ResponsiveContainer } from 'recharts';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -38,7 +39,7 @@ export const AXIS_PROPS = {
|
||||
* white box that ignores the token set.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function ChartTooltip({ active, payload, label, valueFormatter, labelFormatter }) {
|
||||
export function ChartTooltip({ active, payload, label, valueFormatter, labelFormatter }: DsProps) {
|
||||
if (!active || !payload?.length) return null;
|
||||
|
||||
return (
|
||||
@@ -71,7 +72,7 @@ export function ChartTooltip({ active, payload, label, valueFormatter, labelForm
|
||||
* A legend that reads as part of the card rather than as chart furniture.
|
||||
* Items: `{ label, color, value? }`.
|
||||
*/
|
||||
export function ChartLegend({ items = [], className }) {
|
||||
export function ChartLegend({ items = [], className }: DsProps) {
|
||||
return (
|
||||
<div className={cn('flex flex-wrap items-center gap-x-4 gap-y-2', className)}>
|
||||
{items.map((item) => (
|
||||
@@ -118,7 +119,7 @@ export function ChartContainer({
|
||||
raw = false,
|
||||
footer,
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
if (loading) return <SkeletonChart className={className} height={height} />;
|
||||
|
||||
return (
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { ArrowDown, ArrowUp, ChevronsUpDown, Inbox } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -60,7 +61,7 @@ export function DataTable({
|
||||
className,
|
||||
rowClassName,
|
||||
stickyHeader = false,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
/* ── Sorting ─────────────────────────────────────────────────────────── */
|
||||
/* Row height follows the account's density preference. Only the vertical
|
||||
padding changes — same columns, same type, same behaviour. */
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet';
|
||||
@@ -41,7 +42,7 @@ export function Drawer({
|
||||
className,
|
||||
/** Hides the header for a fully custom panel (the mobile nav does this). */
|
||||
bare = false,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const isVertical = side === 'top' || side === 'bottom';
|
||||
|
||||
return (
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -25,7 +26,7 @@ export function EmptyState({
|
||||
variant = 'empty',
|
||||
size = 'default',
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const renderAction = (spec, buttonVariant) => {
|
||||
if (!spec) return null;
|
||||
if (React.isValidElement(spec)) return spec;
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
@@ -19,7 +20,7 @@ export function Field({
|
||||
inline = false,
|
||||
className,
|
||||
children,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const reactId = React.useId();
|
||||
const id = htmlFor || reactId;
|
||||
const hintId = hint ? `${id}-hint` : undefined;
|
||||
@@ -27,11 +28,15 @@ export function Field({
|
||||
const describedBy = [errorId, hintId].filter(Boolean).join(' ') || undefined;
|
||||
|
||||
// Only clone when the child is a single element that can accept the wiring.
|
||||
/* `isValidElement` narrows to `ReactElement<unknown>`, whose `props` is
|
||||
`unknown` — so reading `children.props.id` to preserve a caller's own id
|
||||
does not compile. The cast says what the guard has already established and
|
||||
what the runtime relies on: this is an element with props. */
|
||||
const control = React.isValidElement(children)
|
||||
? React.cloneElement(children, {
|
||||
id: children.props.id || id,
|
||||
'aria-describedby': children.props['aria-describedby'] || describedBy,
|
||||
'aria-invalid': error ? true : children.props['aria-invalid'],
|
||||
? React.cloneElement(children as React.ReactElement<Record<string, any>>, {
|
||||
id: (children.props as Record<string, any>).id || id,
|
||||
'aria-describedby': (children.props as Record<string, any>)['aria-describedby'] || describedBy,
|
||||
'aria-invalid': error ? true : (children.props as Record<string, any>)['aria-invalid'],
|
||||
})
|
||||
: children;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { SlidersHorizontal, X } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -37,7 +38,7 @@ export function FilterBar({
|
||||
/** Value that means "no filter" for select-type filters. */
|
||||
allValue = 'all',
|
||||
className = '',
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const [expanded, setExpanded] = React.useState(false);
|
||||
|
||||
const isActive = (filter) => {
|
||||
@@ -9,8 +9,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/comp
|
||||
* `label`: an icon-only control with no accessible name is a bug, so the API
|
||||
* makes it impossible to omit. The label doubles as the tooltip.
|
||||
*/
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
export const IconButton = React.forwardRef(
|
||||
export const IconButton: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(
|
||||
({ icon: Icon, label, tooltip = true, size = 'default', side = 'top', ...props }, ref) => {
|
||||
const sizeMap = {
|
||||
xs: 'icon-xs',
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { AlertTriangle, ChevronRight, Info, ShieldAlert, TrendingDown } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -58,7 +59,7 @@ export function InsightRow({
|
||||
onClick = null,
|
||||
actionLabel = 'Review',
|
||||
className = '',
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const s = SEVERITY[severity] || SEVERITY.info;
|
||||
const Comp = onClick ? 'button' : 'div';
|
||||
|
||||
@@ -107,6 +108,6 @@ export function InsightRow({
|
||||
|
||||
/** The list container — dividers between rows, nothing else. */
|
||||
/** @param {any} props */
|
||||
export function InsightList({ children, className = '' }) {
|
||||
export function InsightList({ children, className = '' }: DsProps) {
|
||||
return <div className={cn('divide-y divide-border', className)}>{children}</div>;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ArrowDownRight, ArrowUpRight, Minus } from 'lucide-react';
|
||||
@@ -32,7 +33,7 @@ export function KpiCard({
|
||||
loading = false,
|
||||
onClick,
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const t = TONES[tone] || TONES.brand;
|
||||
|
||||
if (loading) {
|
||||
@@ -112,7 +113,7 @@ export function MetricCard({
|
||||
loading = false,
|
||||
onClick,
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const t = TONES[tone] || TONES.neutral;
|
||||
|
||||
if (loading) {
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
@@ -19,7 +20,7 @@ const GAPS = { sm: 'gap-3', default: 'gap-4', lg: 'gap-6' };
|
||||
* chosen to avoid orphan cards (6 → 2/3/6 rather than 1/3/6).
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function Grid({ cols = 3, gap = 'default', className, children, ...props }) {
|
||||
export function Grid({ cols = 3, gap = 'default', className, children, ...props }: DsProps) {
|
||||
const columns = {
|
||||
1: 'grid-cols-1',
|
||||
2: 'grid-cols-1 sm:grid-cols-2',
|
||||
@@ -38,7 +39,7 @@ export function Grid({ cols = 3, gap = 'default', className, children, ...props
|
||||
|
||||
/** Stack — vertical rhythm. `space` maps to the two spacings pages should use. */
|
||||
/** @param {any} props */
|
||||
export function Stack({ space = 'default', className, children, ...props }) {
|
||||
export function Stack({ space = 'default', className, children, ...props }: DsProps) {
|
||||
const spacing = {
|
||||
xs: 'space-y-2',
|
||||
sm: 'space-y-3',
|
||||
@@ -59,7 +60,7 @@ export function Stack({ space = 'default', className, children, ...props }) {
|
||||
* with its content at consistent spacing.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function PageSection({ title, subtitle, actions, level = 'overline', className, children }) {
|
||||
export function PageSection({ title, subtitle, actions, level = 'overline', className, children }: DsProps) {
|
||||
return (
|
||||
<section className={cn('space-y-3', className)}>
|
||||
{title && (
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -6,7 +7,7 @@ import { cn } from '@/lib/utils';
|
||||
* Spinner — the only spinner in the system.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function Spinner({ size = 'default', className = '', label = 'Loading' }) {
|
||||
export function Spinner({ size = 'default', className = '', label = 'Loading' }: DsProps) {
|
||||
const sizes = { xs: 'w-3.5 h-3.5', sm: 'w-4 h-4', default: 'w-6 h-6', lg: 'w-8 h-8' };
|
||||
return (
|
||||
<Loader2
|
||||
@@ -25,7 +26,7 @@ export function Spinner({ size = 'default', className = '', label = 'Loading' })
|
||||
* final layout prevents the content jump a spinner always causes.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function LoadingState({ message = '', size = 'default', className = '' }) {
|
||||
export function LoadingState({ message = '', size = 'default', className = '' }: DsProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -45,7 +46,7 @@ export function LoadingState({ message = '', size = 'default', className = '' })
|
||||
* card headers, or beside a control that is refreshing.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function InlineLoading({ message = 'Loading…', className = '' }) {
|
||||
export function InlineLoading({ message = 'Loading…', className = '' }: DsProps) {
|
||||
return (
|
||||
<span className={cn('inline-flex items-center gap-2 text-body-sm text-ink-3', className)}>
|
||||
<Spinner size="sm" />
|
||||
@@ -59,7 +60,7 @@ export function InlineLoading({ message = 'Loading…', className = '' }) {
|
||||
* height stable so the page does not jump. Used by DataTable when refetching.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function LoadingOverlay({ show = false, message = '', className = '' }) {
|
||||
export function LoadingOverlay({ show = false, message = '', className = '' }: DsProps) {
|
||||
if (!show) return null;
|
||||
return (
|
||||
<div
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { ArrowDownRight, ArrowUpRight, Minus } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -58,7 +59,7 @@ function Delta({ delta, label, invert }) {
|
||||
}
|
||||
|
||||
/** @param {any} props */
|
||||
export function MetricStrip({ items = [], columns, className, loading = false }) {
|
||||
export function MetricStrip({ items = [], columns, className, loading = false }: DsProps) {
|
||||
const count = columns ?? Math.min(items.length, 6);
|
||||
|
||||
const gridCols = {
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
@@ -39,7 +40,7 @@ export function Modal({
|
||||
className,
|
||||
/** Blocks closing — use while a submit is in flight. */
|
||||
busy = false,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={busy ? undefined : onOpenChange}>
|
||||
<DialogContent
|
||||
@@ -100,7 +101,7 @@ export function ConfirmModal({
|
||||
tone = 'destructive',
|
||||
icon = null,
|
||||
busy = false,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { Check, ChevronDown, X } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -25,7 +26,7 @@ export function MultiSelect({
|
||||
className = '',
|
||||
align = 'start',
|
||||
emptyMessage = 'No options',
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [query, setQuery] = React.useState('');
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -22,7 +23,7 @@ export function PageHeader({
|
||||
size = 'title',
|
||||
animate = true,
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const Wrapper = animate ? motion.div : 'div';
|
||||
const motionProps = animate
|
||||
? {
|
||||
@@ -68,7 +69,7 @@ export function PageHeader({
|
||||
* A dashboard-style greeting header where part of the title is emphasized —
|
||||
* "Good day. Let's hire smarter."
|
||||
*/
|
||||
export function HeroHeader({ lead, highlight, subtitle, actions, className }) {
|
||||
export function HeroHeader({ lead, highlight, subtitle, actions, className }: DsProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -12 }}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -24,7 +25,10 @@ export function buildPageRange(current, total, siblings = 1) {
|
||||
const showLeftEllipsis = left > 2;
|
||||
const showRightEllipsis = right < total - 1;
|
||||
|
||||
const pages = [1];
|
||||
/* Page numbers with '…' markers between them — a real mixed array, which is
|
||||
why the renderer tests `entry === '…'` before treating it as a number.
|
||||
Inference took the seed `[1]` as `number[]` and rejected the markers. */
|
||||
const pages: (number | string)[] = [1];
|
||||
if (showLeftEllipsis) pages.push('…');
|
||||
for (let p = Math.max(2, left); p <= Math.min(total - 1, right); p += 1) pages.push(p);
|
||||
if (showRightEllipsis) pages.push('…');
|
||||
@@ -47,7 +51,7 @@ export function Pagination({
|
||||
onPageSizeChange,
|
||||
pageSizeOptions = [10, 25, 50, 100],
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
if (pageCount <= 1 && !onPageSizeChange) return null;
|
||||
|
||||
const from = totalItems != null && pageSize ? (page - 1) * pageSize + 1 : null;
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { Check } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -45,7 +46,7 @@ export function ProgressBar({
|
||||
valueSuffix = '',
|
||||
className,
|
||||
trackClassName,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const pct = clamp((Number(value) / max) * 100);
|
||||
const resolvedTone = tone === 'score' ? toneForScore(pct) : tone;
|
||||
|
||||
@@ -110,7 +111,7 @@ export function ProgressRing({
|
||||
/** Small text below the label. */
|
||||
footnote,
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const radius = (size - strokeWidth) / 2;
|
||||
const circumference = 2 * Math.PI * radius;
|
||||
const ratio = Math.max(0, Math.min(1, (Number(value) - min) / (max - min)));
|
||||
@@ -178,7 +179,7 @@ export function ProgressRing({
|
||||
* at a glance without relying on colour.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function ProgressSteps({ steps = [], current = 0, className = '', onStepClick = null }) {
|
||||
export function ProgressSteps({ steps = [], current = 0, className = '', onStepClick = null }: DsProps) {
|
||||
const normalized = steps.map((s) => (typeof s === 'string' ? { label: s } : s));
|
||||
|
||||
return (
|
||||
@@ -243,7 +244,7 @@ export function ProgressSteps({ steps = [], current = 0, className = '', onStepC
|
||||
* dimensions are listed with a weight and a value.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function ScoreMeter({ label, value, weight, tone = 'score', className }) {
|
||||
export function ScoreMeter({ label, value, weight, tone = 'score', className }: DsProps) {
|
||||
return (
|
||||
<div className={cn('space-y-1.5', className)}>
|
||||
<div className="flex items-baseline justify-between gap-2">
|
||||
@@ -10,8 +10,7 @@ import { inputVariants } from '@/components/ui/input';
|
||||
* without re-running expensive work, while the field itself stays instantly
|
||||
* responsive. Pass `debounce={0}` for immediate updates.
|
||||
*/
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
export const SearchInput = React.forwardRef(
|
||||
export const SearchInput: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(
|
||||
(
|
||||
{
|
||||
value,
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -21,7 +22,7 @@ export function SectionHeader({
|
||||
onViewAll,
|
||||
viewAllLabel = 'View all',
|
||||
className,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
if (level === 'overline') {
|
||||
return (
|
||||
<div className={cn('flex items-center justify-between gap-3 mb-3', className)}>
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
@@ -10,7 +11,7 @@ import { cn } from '@/lib/utils';
|
||||
* `prefers-reduced-motion` (see index.css).
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function Skeleton({ className = '', radius = 'md', ...props }) {
|
||||
export function Skeleton({ className = '', radius = 'md', ...props }: DsProps) {
|
||||
return (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
@@ -33,7 +34,7 @@ export function Skeleton({ className = '', radius = 'md', ...props }) {
|
||||
|
||||
/** Paragraph placeholder. The last line is short, as real text is. */
|
||||
/** @param {any} props */
|
||||
export function SkeletonText({ lines = 3, className = '' }) {
|
||||
export function SkeletonText({ lines = 3, className = '' }: DsProps) {
|
||||
return (
|
||||
<div className={cn('space-y-2', className)} role="status" aria-label="Loading content">
|
||||
{Array.from({ length: lines }).map((_, i) => (
|
||||
@@ -48,7 +49,7 @@ export function SkeletonText({ lines = 3, className = '' }) {
|
||||
|
||||
/** Matches KpiCard: icon tile, big number, caption. */
|
||||
/** @param {any} props */
|
||||
export function SkeletonKpi({ className = '' }) {
|
||||
export function SkeletonKpi({ className = '' }: DsProps) {
|
||||
return (
|
||||
<div className={cn('glass-card border border-white/60 rounded-2xl p-4 shadow-sm', className)}>
|
||||
<Skeleton className="w-10 h-10 rounded-xl mb-3" />
|
||||
@@ -60,7 +61,7 @@ export function SkeletonKpi({ className = '' }) {
|
||||
|
||||
/** Matches a list row: avatar, two lines of text, trailing value. */
|
||||
/** @param {any} props */
|
||||
export function SkeletonRow({ className = '' }) {
|
||||
export function SkeletonRow({ className = '' }: DsProps) {
|
||||
return (
|
||||
<div className={cn('flex items-center gap-3 py-3', className)}>
|
||||
<Skeleton className="w-9 h-9" radius="full" />
|
||||
@@ -75,7 +76,7 @@ export function SkeletonRow({ className = '' }) {
|
||||
|
||||
/** Matches a card in a grid: title, meta, stat row. */
|
||||
/** @param {any} props */
|
||||
export function SkeletonCard({ className = '' }) {
|
||||
export function SkeletonCard({ className = '' }: DsProps) {
|
||||
return (
|
||||
<div className={cn('glass-card border border-white/60 rounded-2xl p-5 shadow-sm', className)}>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
@@ -100,7 +101,7 @@ export function SkeletonCard({ className = '' }) {
|
||||
|
||||
/** Matches DataTable: header row plus n body rows. */
|
||||
/** @param {any} props */
|
||||
export function SkeletonTable({ rows = 5, columns = 4, className = '' }) {
|
||||
export function SkeletonTable({ rows = 5, columns = 4, className = '' }: DsProps) {
|
||||
return (
|
||||
<div className={cn('overflow-hidden', className)} role="status" aria-label="Loading table">
|
||||
<div className="flex items-center gap-4 px-4 py-3 border-b border-border bg-surface-subtle">
|
||||
@@ -121,7 +122,7 @@ export function SkeletonTable({ rows = 5, columns = 4, className = '' }) {
|
||||
|
||||
/** Matches ChartContainer: title, legend, plot area. */
|
||||
/** @param {any} props */
|
||||
export function SkeletonChart({ className = '', height = 240 }) {
|
||||
export function SkeletonChart({ className = '', height = 240 }: DsProps) {
|
||||
return (
|
||||
<div className={cn('glass-card border border-white/60 rounded-2xl p-6 shadow-sm', className)}>
|
||||
<Skeleton className="h-3.5 w-40 mb-2" />
|
||||
@@ -137,7 +138,7 @@ export function SkeletonChart({ className = '', height = 240 }) {
|
||||
|
||||
/** n SkeletonRows inside a surface — the common "loading a list" case. */
|
||||
/** @param {any} props */
|
||||
export function SkeletonList({ rows = 5, className = '' }) {
|
||||
export function SkeletonList({ rows = 5, className = '' }: DsProps) {
|
||||
return (
|
||||
<div className={cn('divide-y divide-border', className)} role="status" aria-label="Loading list">
|
||||
{Array.from({ length: rows }).map((_, i) => (
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@@ -78,7 +79,7 @@ const DOT_COLOR = {
|
||||
* much work; it also gives colour-blind users a second cue alongside the label.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function StatusBadge({ status, label, tone, dot = false, size = 'default', className, ...props }) {
|
||||
export function StatusBadge({ status, label, tone, dot = false, size = 'default', className, ...props }: DsProps) {
|
||||
const entry = STATUS_MAP[status] || {};
|
||||
const resolvedTone = tone || entry.tone || 'neutral';
|
||||
const resolvedLabel = label || entry.label || humanize(status);
|
||||
@@ -55,8 +55,7 @@ const surfaceVariants = cva(
|
||||
}
|
||||
);
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Surface = React.forwardRef(
|
||||
const Surface: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(
|
||||
({ className, variant, elevation, radius, padding, interactive, as, ...props }, ref) => {
|
||||
const Comp = as || 'div';
|
||||
return (
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -25,7 +26,7 @@ export function Tabs({
|
||||
layoutGroupId,
|
||||
className,
|
||||
ariaLabel = 'Views',
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const normalized = tabs.map((t) => (typeof t === 'string' ? { value: t, label: t } : t));
|
||||
const fallbackId = React.useId();
|
||||
const groupId = layoutGroupId || fallbackId;
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { StatusBadge } from '@/components/ds/StatusBadge';
|
||||
@@ -21,7 +22,7 @@ const TONE_DOT = {
|
||||
* timeline can be nested inside a scrolling card without the rail detaching.
|
||||
*/
|
||||
/** @param {any} props */
|
||||
export function Timeline({ items = [], className = '', compact = false }) {
|
||||
export function Timeline({ items = [], className = '', compact = false }: DsProps) {
|
||||
return (
|
||||
<ol className={cn('relative', className)}>
|
||||
{items.map((item, i) => {
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from './props';
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
@@ -20,7 +21,7 @@ export function Toggle({
|
||||
align = 'end',
|
||||
className,
|
||||
id: providedId,
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const reactId = React.useId();
|
||||
const id = providedId || reactId;
|
||||
const descriptionId = description ? `${id}-description` : undefined;
|
||||
@@ -107,7 +108,7 @@ export function SegmentedToggle({
|
||||
variant = 'brand',
|
||||
className = '',
|
||||
ariaLabel = '',
|
||||
}) {
|
||||
}: DsProps) {
|
||||
const normalized = options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));
|
||||
const tone = SEGMENT_VARIANTS[variant] || SEGMENT_VARIANTS.brand;
|
||||
|
||||
22
src/components/ds/props.ts
Normal file
22
src/components/ds/props.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* The props bag a design-system component accepts.
|
||||
*
|
||||
* `any`-valued and open, and that is a faithful description rather than a
|
||||
* retreat. These components carried no PropTypes and no validation, so in the
|
||||
* JavaScript every prop was optional and every extra prop was passed through to
|
||||
* the underlying element. TypeScript infers a destructured parameter without a
|
||||
* default as REQUIRED, which invents a rule the component never had and
|
||||
* rejects call sites that have always worked — 260 of them across pages this
|
||||
* phase does not touch.
|
||||
*
|
||||
* The prop NAMES are not lost: every component still destructures them by name
|
||||
* in its own signature, which is where a reader looks anyway. What is deferred
|
||||
* is per-prop types, and the place to add those is each component's own
|
||||
* interface, one at a time, with its call sites checked — not a sweep that
|
||||
* guesses ninety-five of them at once.
|
||||
*
|
||||
* This alias exists so that decision is recorded once and is greppable when
|
||||
* someone comes to tighten it, rather than being thirty separate `: any`s with
|
||||
* no explanation between them.
|
||||
*/
|
||||
export type DsProps = Record<string, any>;
|
||||
@@ -1,4 +1,5 @@
|
||||
import { toast as hotToast } from 'react-hot-toast';
|
||||
import type { ToastOptions } from 'react-hot-toast';
|
||||
|
||||
/**
|
||||
* Toast — transient confirmation of a user action.
|
||||
@@ -27,8 +28,12 @@ const BASE_STYLE = {
|
||||
|
||||
const DURATIONS = { success: 2600, error: 4200, info: 3000, loading: Infinity };
|
||||
|
||||
const withDefaults = (options = {}) => ({
|
||||
position: /** @type {import('react-hot-toast').ToastPosition} */ ('bottom-center'),
|
||||
/* `ToastOptions` is react-hot-toast's own type, so `position` narrows to its
|
||||
`ToastPosition` union rather than widening to `string` — which is what made
|
||||
every call below unassignable. `Partial` because the callers pass a subset,
|
||||
including none at all. */
|
||||
const withDefaults = (options: Partial<ToastOptions> = {}): Partial<ToastOptions> => ({
|
||||
position: 'bottom-center',
|
||||
...options,
|
||||
style: { ...BASE_STYLE, ...(options.style || {}) },
|
||||
});
|
||||
@@ -42,8 +42,7 @@ const badgeVariants = cva(
|
||||
}
|
||||
)
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Badge = React.forwardRef(({ className, variant, size, shape, ...props }, ref) => (
|
||||
const Badge: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, variant, size, shape, ...props }, ref) => (
|
||||
<div ref={ref} className={cn(badgeVariants({ variant, size, shape }), className)} {...props} />
|
||||
))
|
||||
Badge.displayName = "Badge"
|
||||
@@ -1,17 +1,16 @@
|
||||
import type { DsProps } from '@/components/ds/props';
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Breadcrumb = React.forwardRef(
|
||||
const Breadcrumb: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(
|
||||
({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />
|
||||
)
|
||||
Breadcrumb.displayName = "Breadcrumb"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const BreadcrumbList = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const BreadcrumbList: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<ol
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -22,8 +21,7 @@ const BreadcrumbList = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
BreadcrumbList.displayName = "BreadcrumbList"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const BreadcrumbItem = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const BreadcrumbItem: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<li
|
||||
ref={ref}
|
||||
className={cn("inline-flex items-center gap-1.5", className)}
|
||||
@@ -31,8 +29,7 @@ const BreadcrumbItem = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
BreadcrumbItem.displayName = "BreadcrumbItem"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const BreadcrumbLink = React.forwardRef(({ asChild, className, ...props }, ref) => {
|
||||
const BreadcrumbLink: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ asChild, className, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "a"
|
||||
|
||||
return (
|
||||
@@ -44,8 +41,7 @@ const BreadcrumbLink = React.forwardRef(({ asChild, className, ...props }, ref)
|
||||
})
|
||||
BreadcrumbLink.displayName = "BreadcrumbLink"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const BreadcrumbPage = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const BreadcrumbPage: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<span
|
||||
ref={ref}
|
||||
role="link"
|
||||
@@ -61,7 +57,7 @@ const BreadcrumbSeparator = ({
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}) => (
|
||||
}: DsProps) => (
|
||||
<li
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
@@ -76,7 +72,7 @@ BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
|
||||
const BreadcrumbEllipsis = ({
|
||||
className,
|
||||
...props
|
||||
}) => (
|
||||
}: DsProps) => (
|
||||
<span
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
@@ -82,8 +82,7 @@ const buttonVariants = cva(
|
||||
}
|
||||
)
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Button = React.forwardRef((
|
||||
const Button: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>((
|
||||
{ className, variant, size, shape, block, asChild = false, loading = false, disabled, children, ...props },
|
||||
ref
|
||||
) => {
|
||||
@@ -2,8 +2,7 @@ import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Card = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const Card: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("rounded-xl border bg-card text-card-foreground shadow", className)}
|
||||
@@ -11,8 +10,7 @@ const Card = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
Card.displayName = "Card"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const CardHeader: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||
@@ -20,8 +18,7 @@ const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
CardHeader.displayName = "CardHeader"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const CardTitle: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("font-semibold leading-none tracking-tight", className)}
|
||||
@@ -29,8 +26,7 @@ const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
CardTitle.displayName = "CardTitle"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const CardDescription: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
@@ -38,14 +34,12 @@ const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
CardDescription.displayName = "CardDescription"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const CardContent = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const CardContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||
))
|
||||
CardContent.displayName = "CardContent"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const CardFooter: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex items-center p-6 pt-0", className)}
|
||||
@@ -4,8 +4,7 @@ import { Check } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Checkbox = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const Checkbox: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from '@/components/ds/props';
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
@@ -14,8 +15,7 @@ const DialogPortal = DialogPrimitive.Portal
|
||||
|
||||
const DialogClose = DialogPrimitive.Close
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const DialogOverlay: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -26,8 +26,7 @@ const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DialogContent = React.forwardRef(({ className, children, ...props }, ref) => (
|
||||
const DialogContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
@@ -52,7 +51,7 @@ DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
const DialogHeader = ({
|
||||
className = '',
|
||||
...props
|
||||
}) => (
|
||||
}: DsProps) => (
|
||||
<div
|
||||
className={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)}
|
||||
{...props} />
|
||||
@@ -63,15 +62,14 @@ DialogHeader.displayName = "DialogHeader"
|
||||
const DialogFooter = ({
|
||||
className = '',
|
||||
...props
|
||||
}) => (
|
||||
}: DsProps) => (
|
||||
<div
|
||||
className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...props} />
|
||||
)
|
||||
DialogFooter.displayName = "DialogFooter"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const DialogTitle: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||
@@ -79,8 +77,7 @@ const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DialogDescription = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const DialogDescription: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from '@/components/ds/props';
|
||||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||
@@ -16,8 +17,7 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => (
|
||||
const DropdownMenuSubTrigger: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -33,8 +33,7 @@ const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, .
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const DropdownMenuSubContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -46,8 +45,7 @@ const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) =
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
const DropdownMenuContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
@@ -62,8 +60,7 @@ const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...pr
|
||||
))
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => (
|
||||
const DropdownMenuItem: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -75,8 +72,7 @@ const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref)
|
||||
))
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, ...props }, ref) => (
|
||||
const DropdownMenuCheckboxItem: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, children, checked, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -96,8 +92,7 @@ const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checke
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DropdownMenuRadioItem = React.forwardRef(({ className, children, value, ...props }, ref) => (
|
||||
const DropdownMenuRadioItem: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, children, value, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
value={value}
|
||||
@@ -116,8 +111,7 @@ const DropdownMenuRadioItem = React.forwardRef(({ className, children, value, ..
|
||||
))
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref) => (
|
||||
const DropdownMenuLabel: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
|
||||
@@ -125,8 +119,7 @@ const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref)
|
||||
))
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const DropdownMenuSeparator: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
@@ -137,7 +130,7 @@ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
}: DsProps) => {
|
||||
return (
|
||||
(<span
|
||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||
@@ -9,8 +9,7 @@ const HoverCard = HoverCardPrimitive.Root
|
||||
|
||||
const HoverCardTrigger = HoverCardPrimitive.Trigger
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const HoverCardContent = React.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
const HoverCardContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<HoverCardPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
@@ -72,8 +72,7 @@ function buildSrcSet(parsed, options) {
|
||||
).join(", ")
|
||||
}
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const ImageWrapper = React.forwardRef(({ aspectRatio, className, style, children }, ref) => (
|
||||
const ImageWrapper: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ aspectRatio, className, style, children }, ref) => (
|
||||
<span
|
||||
ref={ref}
|
||||
className={cn("inline-block relative", className)}
|
||||
@@ -84,8 +83,7 @@ const ImageWrapper = React.forwardRef(({ aspectRatio, className, style, children
|
||||
))
|
||||
ImageWrapper.displayName = "ImageWrapper"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const ResponsiveImage = React.forwardRef(
|
||||
const ResponsiveImage: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(
|
||||
({ parsed, fittingType, focalPoint, quality, className, style, aspectRatio, onLoad, ...props }, parentRef) => {
|
||||
const wrapperRef = React.useRef(null)
|
||||
const imgRef = React.useRef(null)
|
||||
@@ -174,8 +172,7 @@ ResponsiveImage.displayName = "ResponsiveImage"
|
||||
* server-side, optionally anchored at a focal point. Other URLs render as a
|
||||
* plain <img>. Failed loads swap to a fallback image.
|
||||
*/
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Image = React.forwardRef(
|
||||
const Image: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(
|
||||
(
|
||||
{
|
||||
src,
|
||||
@@ -34,8 +34,7 @@ const inputVariants = cva(
|
||||
}
|
||||
)
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Input = React.forwardRef(({ className, type, size, shape, ...props }, ref) => (
|
||||
const Input: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, type, size, shape, ...props }, ref) => (
|
||||
<input
|
||||
type={type}
|
||||
ref={ref}
|
||||
@@ -8,8 +8,7 @@ const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
)
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Label = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const Label: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
@@ -9,8 +9,7 @@ const PopoverTrigger = PopoverPrimitive.Trigger
|
||||
|
||||
const PopoverAnchor = PopoverPrimitive.Anchor
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
const PopoverContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
@@ -4,14 +4,12 @@ import { Circle } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const RadioGroup = React.forwardRef(({ className, ...props }, ref) => {
|
||||
const RadioGroup: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => {
|
||||
return (<RadioGroupPrimitive.Root className={cn("grid gap-2", className)} {...props} ref={ref} />);
|
||||
})
|
||||
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const RadioGroupItem = React.forwardRef(({ className = '', value, ...props }, ref) => {
|
||||
const RadioGroupItem: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className = '', value, ...props }, ref) => {
|
||||
return (
|
||||
(<RadioGroupPrimitive.Item
|
||||
ref={ref}
|
||||
@@ -12,8 +12,7 @@ const SelectGroup = SelectPrimitive.Group
|
||||
|
||||
const SelectValue = SelectPrimitive.Value
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (
|
||||
const SelectTrigger: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -29,8 +28,7 @@ const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref)
|
||||
))
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const SelectScrollUpButton: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
ref={ref}
|
||||
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
||||
@@ -40,8 +38,7 @@ const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) =>
|
||||
))
|
||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SelectScrollDownButton = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const SelectScrollDownButton: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
ref={ref}
|
||||
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
||||
@@ -52,8 +49,7 @@ const SelectScrollDownButton = React.forwardRef(({ className, ...props }, ref) =
|
||||
SelectScrollDownButton.displayName =
|
||||
SelectPrimitive.ScrollDownButton.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => (
|
||||
const SelectContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, children, position = "popper", ...props }, ref) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
@@ -77,8 +73,7 @@ const SelectContent = React.forwardRef(({ className, children, position = "poppe
|
||||
))
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const SelectLabel: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
||||
@@ -93,7 +88,7 @@ SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||
trap: Radix then has no value to match against, no item is ever `isSelected`,
|
||||
the trigger's value node never receives any item text, and every closed select
|
||||
renders as an empty pill with nothing but a chevron. */
|
||||
const SelectItem = React.forwardRef(({ className = '', children, value, ...props }, ref) => (
|
||||
const SelectItem = React.forwardRef<any, any>(({ className = '', children, value, ...props }, ref) => (
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
value={value}
|
||||
@@ -112,8 +107,7 @@ const SelectItem = React.forwardRef(({ className = '', children, value, ...props
|
||||
))
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const SelectSeparator: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DsProps } from '@/components/ds/props';
|
||||
"use client";
|
||||
import * as React from "react"
|
||||
import * as SheetPrimitive from "@radix-ui/react-dialog"
|
||||
@@ -14,8 +15,7 @@ const SheetClose = SheetPrimitive.Close
|
||||
|
||||
const SheetPortal = SheetPrimitive.Portal
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SheetOverlay = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const SheetOverlay: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
@@ -45,8 +45,7 @@ const sheetVariants = cva(
|
||||
}
|
||||
)
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SheetContent = React.forwardRef(({ side = "right", className, children, ...props }, ref) => (
|
||||
const SheetContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ side = "right", className, children, ...props }, ref) => (
|
||||
<SheetPortal>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
|
||||
@@ -64,7 +63,7 @@ SheetContent.displayName = SheetPrimitive.Content.displayName
|
||||
const SheetHeader = ({
|
||||
className,
|
||||
...props
|
||||
}) => (
|
||||
}: DsProps) => (
|
||||
<div
|
||||
className={cn("flex flex-col space-y-2 text-center sm:text-left", className)}
|
||||
{...props} />
|
||||
@@ -74,15 +73,14 @@ SheetHeader.displayName = "SheetHeader"
|
||||
const SheetFooter = ({
|
||||
className,
|
||||
...props
|
||||
}) => (
|
||||
}: DsProps) => (
|
||||
<div
|
||||
className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...props} />
|
||||
)
|
||||
SheetFooter.displayName = "SheetFooter"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SheetTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const SheetTitle: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold text-foreground", className)}
|
||||
@@ -90,8 +88,7 @@ const SheetTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
))
|
||||
SheetTitle.displayName = SheetPrimitive.Title.displayName
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const SheetDescription = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const SheetDescription: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
@@ -3,8 +3,7 @@ import * as SliderPrimitive from "@radix-ui/react-slider"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Slider = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const Slider: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SliderPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative flex w-full touch-none select-none items-center", className)}
|
||||
@@ -3,8 +3,7 @@ import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Switch = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const Switch: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors duration-base ease-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-krow-blue/60 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-krow-blue data-[state=unchecked]:bg-surface-sunken data-[state=unchecked]:border-border",
|
||||
@@ -2,8 +2,7 @@ import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Textarea = React.forwardRef(({ className, ...props }, ref) => {
|
||||
const Textarea: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
(<textarea
|
||||
className={cn(
|
||||
@@ -3,8 +3,7 @@ import { cva } from "class-variance-authority";
|
||||
import { X } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const ToastProvider = React.forwardRef(({ ...props }, ref) => (
|
||||
const ToastProvider: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className="fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]"
|
||||
@@ -13,8 +12,7 @@ const ToastProvider = React.forwardRef(({ ...props }, ref) => (
|
||||
));
|
||||
ToastProvider.displayName = "ToastProvider";
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const ToastViewport = React.forwardRef(({ ...props }, ref) => (
|
||||
const ToastViewport: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className="fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]"
|
||||
@@ -39,8 +37,7 @@ const toastVariants = cva(
|
||||
}
|
||||
);
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const Toast = React.forwardRef(({ className, variant, ...props }, ref) => {
|
||||
const Toast: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, variant, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
@@ -51,8 +48,7 @@ const Toast = React.forwardRef(({ className, variant, ...props }, ref) => {
|
||||
});
|
||||
Toast.displayName = "Toast";
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const ToastAction = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const ToastAction: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -64,8 +60,7 @@ const ToastAction = React.forwardRef(({ className, ...props }, ref) => (
|
||||
));
|
||||
ToastAction.displayName = "ToastAction";
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const ToastClose = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const ToastClose: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<button
|
||||
ref={ref}
|
||||
className={cn(
|
||||
@@ -80,8 +75,7 @@ const ToastClose = React.forwardRef(({ className, ...props }, ref) => (
|
||||
));
|
||||
ToastClose.displayName = "ToastClose";
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const ToastTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const ToastTitle: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("text-sm font-semibold", className)}
|
||||
@@ -90,8 +84,7 @@ const ToastTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||
));
|
||||
ToastTitle.displayName = "ToastTitle";
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const ToastDescription = React.forwardRef(({ className, ...props }, ref) => (
|
||||
const ToastDescription: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("text-sm opacity-90", className)}
|
||||
@@ -11,8 +11,7 @@ const Tooltip = TooltipPrimitive.Root
|
||||
|
||||
const TooltipTrigger = TooltipPrimitive.Trigger
|
||||
|
||||
/** @type {React.ForwardRefExoticComponent<any>} */
|
||||
const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
const TooltipContent: React.ForwardRefExoticComponent<any> = React.forwardRef<any, any>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<TooltipPrimitive.Portal>
|
||||
<TooltipPrimitive.Content
|
||||
ref={ref}
|
||||
Reference in New Issue
Block a user