@upbound/monarch-blocks 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/utils.ts","../src/page-header.tsx"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { cn } from '@/lib/utils';\n\nfunction PageHeader({ className, children, ...props }: React.ComponentProps<'div'>) {\n return (\n <div data-slot=\"page-header\" className={cn('flex w-full items-start justify-between gap-4', className)} {...props}>\n {children}\n </div>\n );\n}\n\nfunction PageHeaderAvatar({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"page-header-avatar\" className={cn('shrink-0 self-center', className)} {...props} />;\n}\n\nfunction PageHeaderContent({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"page-header-content\" className={cn('flex flex-1 flex-col gap-1', className)} {...props} />;\n}\n\nfunction PageHeaderTitle({ className, ...props }: React.ComponentProps<'h1'>) {\n return <h1 data-slot=\"page-header-title\" className={cn('text-h1 text-foreground', className)} {...props} />;\n}\n\nfunction PageHeaderDescription({ className, ...props }: React.ComponentProps<'p'>) {\n return (\n <p data-slot=\"page-header-description\" className={cn('text-body text-muted-foreground', className)} {...props} />\n );\n}\n\nfunction PageHeaderMeta({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"page-header-meta\"\n className={cn(\n 'text-body text-muted-foreground flex flex-wrap items-center gap-4',\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-(--icon-default)\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction PageHeaderActions({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"page-header-actions\" className={cn('flex items-center gap-2', className)} {...props} />;\n}\n\nfunction PageHeaderTabs({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"page-header-tabs\" className={cn('border-b', className)} {...props} />;\n}\n\nexport {\n PageHeader,\n PageHeaderAvatar,\n PageHeaderContent,\n PageHeaderTitle,\n PageHeaderDescription,\n PageHeaderMeta,\n PageHeaderActions,\n PageHeaderTabs,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AC5BI;AAFJ,SAAS,WAAW,IAAgE;AAAhE,eAAE,aAAW,SAFjC,IAEoB,IAA0B,kBAA1B,IAA0B,CAAxB,aAAW;AAC/B,SACE,oBAAC,sCAAI,aAAU,eAAc,WAAW,GAAG,iDAAiD,SAAS,KAAO,QAA3G,EACE,WACH;AAEJ;AAEA,SAAS,iBAAiB,IAAsD;AAAtD,eAAE,YAV5B,IAU0B,IAAgB,kBAAhB,IAAgB,CAAd;AAC1B,SAAO,oBAAC,wBAAI,aAAU,sBAAqB,WAAW,GAAG,wBAAwB,SAAS,KAAO,MAAO;AAC1G;AAEA,SAAS,kBAAkB,IAAsD;AAAtD,eAAE,YAd7B,IAc2B,IAAgB,kBAAhB,IAAgB,CAAd;AAC3B,SAAO,oBAAC,wBAAI,aAAU,uBAAsB,WAAW,GAAG,8BAA8B,SAAS,KAAO,MAAO;AACjH;AAEA,SAAS,gBAAgB,IAAqD;AAArD,eAAE,YAlB3B,IAkByB,IAAgB,kBAAhB,IAAgB,CAAd;AACzB,SAAO,oBAAC,uBAAG,aAAU,qBAAoB,WAAW,GAAG,2BAA2B,SAAS,KAAO,MAAO;AAC3G;AAEA,SAAS,sBAAsB,IAAoD;AAApD,eAAE,YAtBjC,IAsB+B,IAAgB,kBAAhB,IAAgB,CAAd;AAC/B,SACE,oBAAC,sBAAE,aAAU,2BAA0B,WAAW,GAAG,mCAAmC,SAAS,KAAO,MAAO;AAEnH;AAEA,SAAS,eAAe,IAAsD;AAAtD,eAAE,YA5B1B,IA4BwB,IAAgB,kBAAhB,IAAgB,CAAd;AACxB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,OACI;AAAA,EACN;AAEJ;AAEA,SAAS,kBAAkB,IAAsD;AAAtD,eAAE,YA1C7B,IA0C2B,IAAgB,kBAAhB,IAAgB,CAAd;AAC3B,SAAO,oBAAC,wBAAI,aAAU,uBAAsB,WAAW,GAAG,2BAA2B,SAAS,KAAO,MAAO;AAC9G;AAEA,SAAS,eAAe,IAAsD;AAAtD,eAAE,YA9C1B,IA8CwB,IAAgB,kBAAhB,IAAgB,CAAd;AACxB,SAAO,oBAAC,wBAAI,aAAU,oBAAmB,WAAW,GAAG,YAAY,SAAS,KAAO,MAAO;AAC5F;","names":[]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/page-header.tsx"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport function sortBy<T>(items: T[], getKey: (item: T) => string): T[] {\n return [...items].sort((a, b) => getKey(a).localeCompare(getKey(b)));\n}\n","import { cn } from '@/lib/utils';\n\nfunction PageHeader({ className, children, ...props }: React.ComponentProps<'div'>) {\n return (\n <div data-slot=\"page-header\" className={cn('flex w-full items-start justify-between gap-4', className)} {...props}>\n {children}\n </div>\n );\n}\n\nfunction PageHeaderAvatar({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"page-header-avatar\" className={cn('shrink-0 self-center', className)} {...props} />;\n}\n\nfunction PageHeaderContent({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"page-header-content\" className={cn('flex flex-1 flex-col gap-1', className)} {...props} />;\n}\n\nfunction PageHeaderTitle({ className, ...props }: React.ComponentProps<'h1'>) {\n return <h1 data-slot=\"page-header-title\" className={cn('text-h1 text-foreground', className)} {...props} />;\n}\n\nfunction PageHeaderDescription({ className, ...props }: React.ComponentProps<'p'>) {\n return (\n <p data-slot=\"page-header-description\" className={cn('text-body text-muted-foreground', className)} {...props} />\n );\n}\n\nfunction PageHeaderMeta({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"page-header-meta\"\n className={cn(\n 'text-body text-muted-foreground flex flex-wrap items-center gap-4',\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-(--icon-default)\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction PageHeaderActions({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"page-header-actions\" className={cn('flex items-center gap-2', className)} {...props} />;\n}\n\nfunction PageHeaderTabs({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"page-header-tabs\" className={cn('border-b', className)} {...props} />;\n}\n\nexport {\n PageHeader,\n PageHeaderAvatar,\n PageHeaderContent,\n PageHeaderTitle,\n PageHeaderDescription,\n PageHeaderMeta,\n PageHeaderActions,\n PageHeaderTabs,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AC5BI;AAFJ,SAAS,WAAW,IAAgE;AAAhE,eAAE,aAAW,SAFjC,IAEoB,IAA0B,kBAA1B,IAA0B,CAAxB,aAAW;AAC/B,SACE,oBAAC,sCAAI,aAAU,eAAc,WAAW,GAAG,iDAAiD,SAAS,KAAO,QAA3G,EACE,WACH;AAEJ;AAEA,SAAS,iBAAiB,IAAsD;AAAtD,eAAE,YAV5B,IAU0B,IAAgB,kBAAhB,IAAgB,CAAd;AAC1B,SAAO,oBAAC,wBAAI,aAAU,sBAAqB,WAAW,GAAG,wBAAwB,SAAS,KAAO,MAAO;AAC1G;AAEA,SAAS,kBAAkB,IAAsD;AAAtD,eAAE,YAd7B,IAc2B,IAAgB,kBAAhB,IAAgB,CAAd;AAC3B,SAAO,oBAAC,wBAAI,aAAU,uBAAsB,WAAW,GAAG,8BAA8B,SAAS,KAAO,MAAO;AACjH;AAEA,SAAS,gBAAgB,IAAqD;AAArD,eAAE,YAlB3B,IAkByB,IAAgB,kBAAhB,IAAgB,CAAd;AACzB,SAAO,oBAAC,uBAAG,aAAU,qBAAoB,WAAW,GAAG,2BAA2B,SAAS,KAAO,MAAO;AAC3G;AAEA,SAAS,sBAAsB,IAAoD;AAApD,eAAE,YAtBjC,IAsB+B,IAAgB,kBAAhB,IAAgB,CAAd;AAC/B,SACE,oBAAC,sBAAE,aAAU,2BAA0B,WAAW,GAAG,mCAAmC,SAAS,KAAO,MAAO;AAEnH;AAEA,SAAS,eAAe,IAAsD;AAAtD,eAAE,YA5B1B,IA4BwB,IAAgB,kBAAhB,IAAgB,CAAd;AACxB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,OACI;AAAA,EACN;AAEJ;AAEA,SAAS,kBAAkB,IAAsD;AAAtD,eAAE,YA1C7B,IA0C2B,IAAgB,kBAAhB,IAAgB,CAAd;AAC3B,SAAO,oBAAC,wBAAI,aAAU,uBAAsB,WAAW,GAAG,2BAA2B,SAAS,KAAO,MAAO;AAC9G;AAEA,SAAS,eAAe,IAAsD;AAAtD,eAAE,YA9C1B,IA8CwB,IAAgB,kBAAhB,IAAgB,CAAd;AACxB,SAAO,oBAAC,wBAAI,aAAU,oBAAmB,WAAW,GAAG,YAAY,SAAS,KAAO,MAAO;AAC5F;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/relative-time.tsx","../src/lib/utils.ts","../src/hooks/use-mounted.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\nimport { useMounted } from '@/hooks/use-mounted';\n\n// ── Format helpers ─────────────────────────────────────────────────────────────\n//\n// `locale` is `undefined` (browser/runtime default — the viewer's actual\n// locale, per Monarch's \"use locale-aware formatting\" content principle) once\n// mounted client-side, and a fixed `'en-US'` for the server-rendered/first-\n// paint value — the server can't know the viewer's locale ahead of time, and\n// passing a locale that differs between server and client render would\n// hydration-mismatch. Callers gate this via `useMounted()` below, so the\n// locale-aware value replaces the fixed one right after mount (see\n// RelativeTime/AbsoluteTimestamp).\n\n/** Returns a human-readable relative label for `date` vs now. */\nfunction formatRelativeDefault(date: Date, locale: string | undefined): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n\n // Future dates\n if (diffMs < 0) {\n const abs = Math.abs(diffMs);\n const mins = Math.floor(abs / 60000);\n const hrs = Math.floor(mins / 60);\n const days = Math.floor(hrs / 24);\n if (abs < 60000) return 'just now';\n if (mins < 60) return `in ${mins} minute${mins === 1 ? '' : 's'}`;\n if (hrs < 24) return `in ${hrs} hour${hrs === 1 ? '' : 's'}`;\n if (days < 7) return `in ${days} day${days === 1 ? '' : 's'}`;\n if (days < 30) return `in ${Math.floor(days / 7)} week${Math.floor(days / 7) === 1 ? '' : 's'}`;\n return `on ${date.toLocaleDateString(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n })}`;\n }\n\n // Past dates\n const secs = Math.floor(diffMs / 1000);\n const mins = Math.floor(secs / 60);\n const hrs = Math.floor(mins / 60);\n const days = Math.floor(hrs / 24);\n\n if (secs < 60) return 'just now';\n if (mins < 60) return `${mins} minute${mins === 1 ? '' : 's'} ago`;\n if (hrs < 24) return `${hrs} hour${hrs === 1 ? '' : 's'} ago`;\n if (days === 1) return 'yesterday';\n if (days < 7) return `${days} days ago`;\n if (days < 14) return 'last week';\n if (days < 30) return `${Math.floor(days / 7)} weeks ago`;\n\n // > 30 days: fall back to absolute date\n return `on ${date.toLocaleDateString(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n })}`;\n}\n\n/**\n * Compact relative label — abbreviates units for tight horizontal space\n * (tables, KPI cards). Preserves \"ago\", \"in\", \"on\", and \"just now\" so\n * directionality and reference points stay legible at a glance.\n */\nfunction formatRelativeCompact(date: Date, locale: string | undefined): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n\n // Future dates\n if (diffMs < 0) {\n const abs = Math.abs(diffMs);\n const mins = Math.floor(abs / 60000);\n const hrs = Math.floor(mins / 60);\n const days = Math.floor(hrs / 24);\n if (abs < 60000) return 'just now';\n if (mins < 60) return `in ${mins}m`;\n if (hrs < 24) return `in ${hrs}h`;\n if (days < 7) return `in ${days}d`;\n if (days < 30) return `in ${Math.floor(days / 7)}w`;\n return `on ${date.toLocaleDateString(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n })}`;\n }\n\n // Past dates\n const secs = Math.floor(diffMs / 1000);\n const mins = Math.floor(secs / 60);\n const hrs = Math.floor(mins / 60);\n const days = Math.floor(hrs / 24);\n\n if (secs < 60) return 'just now';\n if (mins < 60) return `${mins}m ago`;\n if (hrs < 24) return `${hrs}h ago`;\n if (days < 7) return `${days}d ago`;\n if (days < 30) return `${Math.floor(days / 7)}w ago`;\n\n return `on ${date.toLocaleDateString(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n })}`;\n}\n\nfunction formatRelative(date: Date, variant: 'default' | 'compact', locale: string | undefined): string {\n return variant === 'compact' ? formatRelativeCompact(date, locale) : formatRelativeDefault(date, locale);\n}\n\n/** Returns the update interval in ms appropriate for the current age. */\nfunction updateInterval(date: Date): number {\n const diffMs = Math.abs(Date.now() - date.getTime());\n const diffMin = diffMs / 60000;\n if (diffMin < 60) return 60_000; // update every minute while < 1 hour old\n if (diffMin < 1440) return 300_000; // every 5 min while < 1 day old\n return 3_600_000; // every hour otherwise\n}\n\n/** Formats an absolute tooltip title. */\nfunction absoluteTitle(date: Date, locale: string | undefined): string {\n return date.toLocaleString(locale, {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n timeZoneName: 'short',\n });\n}\n\n// ── Component ──────────────────────────────────────────────────────────────────\n\nexport interface RelativeTimeProps extends Omit<React.TimeHTMLAttributes<HTMLTimeElement>, 'dateTime' | 'title'> {\n /**\n * The timestamp to display. Accepts a `Date`, ISO string, or unix milliseconds.\n */\n date: Date | string | number;\n /**\n * Format variant. `default` produces full-word output (\"5 minutes ago\",\n * \"yesterday\"). `compact` abbreviates units (\"5m ago\", \"1d ago\") for tight\n * horizontal space like tables, KPI cards, or inline metadata.\n */\n variant?: 'default' | 'compact';\n /**\n * Override the tooltip shown on hover. Defaults to the full localized\n * absolute date-time string (e.g. \"Monday, January 20, 2025 at 3:22 PM PST\").\n */\n title?: string;\n}\n\n/**\n * Displays a timestamp as a live-updating relative string (\"5 minutes ago\",\n * \"yesterday\", \"on Nov 18\") with the absolute date in the native tooltip.\n *\n * Falls back to an absolute \"on [Month Day]\" format for dates older than 30 days\n * so that stale timestamps remain legible at a glance.\n *\n * @see https://design.upbound.io/components/date-and-time\n */\nexport function RelativeTime({ date, variant = 'default', title, className, ...props }: RelativeTimeProps) {\n const d = React.useMemo(() => new Date(date), [date]);\n const mounted = useMounted();\n // Fixed locale for the server-rendered/first-paint value (the server can't\n // know the viewer's locale); the viewer's actual locale once mounted.\n const locale = mounted ? undefined : 'en-US';\n\n const [label, setLabel] = React.useState<string>(() => formatRelative(d, variant, locale));\n\n React.useEffect(() => {\n // Re-compute immediately on mount (picks up the viewer's real locale, and\n // avoids the relative label going stale)\n setLabel(formatRelative(d, variant, locale));\n\n const schedule = () => {\n const id = window.setInterval(() => {\n setLabel(formatRelative(d, variant, locale));\n }, updateInterval(d));\n return id;\n };\n const id = schedule();\n return () => window.clearInterval(id);\n }, [d, variant, locale]);\n\n return (\n <time\n dateTime={d.toISOString()}\n title={title ?? absoluteTitle(d, locale)}\n className={cn('tabular-nums', className)}\n {...props}\n >\n {label}\n </time>\n );\n}\n\n// ── Absolute Timestamp ────────────────────────────────────────────────────────\n\n/** Formats am/pm per Content Principles: lowercase, space before, no periods. */\nfunction formatAmPm(date: Date, options: Intl.DateTimeFormatOptions, locale: string | undefined): string {\n const parts = new Intl.DateTimeFormat(locale, options).formatToParts(date);\n let result = '';\n for (const part of parts) {\n if (part.type === 'dayPeriod') {\n result += part.value.toLowerCase().replace(/\\./g, '');\n } else {\n result += part.value;\n }\n }\n return result;\n}\n\nfunction formatAbsolute(date: Date, variant: string, end: Date | undefined, locale: string | undefined): string {\n switch (variant) {\n case 'deadline': {\n const weekday = date.toLocaleDateString(locale, { weekday: 'short' });\n const datePart = date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n const timePart = formatAmPm(date, { hour: 'numeric', minute: '2-digit' }, locale);\n const tz = date.toLocaleTimeString(locale, { timeZoneName: 'short' }).split(' ').pop() ?? '';\n return `${weekday}, ${datePart} \\u00b7 ${timePart} ${tz}`;\n }\n case 'log': {\n const datePart = date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n const timePart = formatAmPm(date, { hour: 'numeric', minute: '2-digit' }, locale);\n const tz = date.toLocaleTimeString(locale, { timeZoneName: 'short' }).split(' ').pop() ?? '';\n return `${datePart}, ${timePart} ${tz}`;\n }\n case 'range': {\n if (!end) return date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n const startYear = date.getFullYear();\n const endYear = end.getFullYear();\n if (startYear === endYear) {\n const start = date.toLocaleDateString(locale, { month: 'short', day: 'numeric' });\n const endStr = end.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n return `${start} \\u2013 ${endStr}`;\n }\n const start = date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n const endStr = end.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n return `${start} \\u2013 ${endStr}`;\n }\n case 'date':\n default:\n return date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n }\n}\n\nexport interface AbsoluteTimestampProps extends Omit<React.TimeHTMLAttributes<HTMLTimeElement>, 'dateTime'> {\n /** The timestamp to display. */\n date: Date | string | number;\n /** Format variant matching the Content Principles absolute timestamp table. */\n variant?: 'deadline' | 'log' | 'date' | 'range';\n /** End date for range variant. */\n end?: Date | string | number;\n}\n\n/**\n * Formats a date as an absolute timestamp following the Content Principles.\n * Use for deadlines, certificate expiry, audit logs, and date-only displays.\n */\nexport function AbsoluteTimestamp({ date, variant = 'date', end, className, ...props }: AbsoluteTimestampProps) {\n const d = React.useMemo(() => new Date(date), [date]);\n const e = React.useMemo(() => (end ? new Date(end) : undefined), [end]);\n const mounted = useMounted();\n // Fixed locale for the server-rendered/first-paint value (the server can't\n // know the viewer's locale); the viewer's actual locale once mounted.\n const locale = mounted ? undefined : 'en-US';\n\n return (\n <time\n dateTime={d.toISOString()}\n title={absoluteTitle(d, locale)}\n className={cn('tabular-nums', className)}\n {...props}\n >\n {formatAbsolute(d, variant, e, locale)}\n </time>\n );\n}\n\n// ── Elapsed Time ──────────────────────────────────────────────────────────────\n\nfunction formatElapsed(totalSeconds: number, variant: string): string {\n const days = Math.floor(totalSeconds / 86400);\n const hours = Math.floor((totalSeconds % 86400) / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = Math.floor(totalSeconds % 60);\n\n switch (variant) {\n case 'expanded': {\n const parts: string[] = [];\n if (days > 0) parts.push(`${days} day${days === 1 ? '' : 's'}`);\n if (hours > 0) parts.push(`${hours} hour${hours === 1 ? '' : 's'}`);\n if (minutes > 0) parts.push(`${minutes} minute${minutes === 1 ? '' : 's'}`);\n if (seconds > 0 || parts.length === 0) parts.push(`${seconds} second${seconds === 1 ? '' : 's'}`);\n return parts.join(', ');\n }\n case 'long': {\n if (days > 0) return `${days}d ${hours}h`;\n if (hours > 0) return `${hours}h ${minutes}m`;\n return `${minutes}m`;\n }\n case 'compact':\n default: {\n if (days > 0) return `${days}d ${hours}h`;\n if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;\n if (minutes > 0) return `${minutes}m ${seconds}s`;\n return `${seconds}s`;\n }\n }\n}\n\nexport interface ElapsedTimeProps extends Omit<React.TimeHTMLAttributes<HTMLTimeElement>, 'dateTime'> {\n /** Total elapsed seconds. Ignored if startedAt is provided. */\n seconds?: number;\n /** Format variant matching the Content Principles elapsed time table. */\n variant?: 'compact' | 'expanded' | 'long';\n /** Live-tick every second for active operations. */\n live?: boolean;\n /** Compute elapsed from a start time instead of a fixed seconds value. */\n startedAt?: Date | string | number;\n}\n\n/**\n * Formats a duration as elapsed time following the Content Principles.\n * Use for reconciliation loops, build jobs, health checks, and running operations.\n */\nexport function ElapsedTime({\n seconds: secondsProp,\n variant = 'compact',\n live = false,\n startedAt,\n className,\n ...props\n}: ElapsedTimeProps) {\n const startDate = React.useMemo(() => (startedAt ? new Date(startedAt) : undefined), [startedAt]);\n\n const computeSeconds = React.useCallback(() => {\n if (startDate) return Math.floor((Date.now() - startDate.getTime()) / 1000);\n return secondsProp ?? 0;\n }, [startDate, secondsProp]);\n\n const [elapsed, setElapsed] = React.useState(computeSeconds);\n\n React.useEffect(() => {\n setElapsed(computeSeconds());\n\n if (!live && !startDate) return;\n\n const id = window.setInterval(() => {\n setElapsed(computeSeconds());\n }, 1000);\n return () => window.clearInterval(id);\n }, [live, startDate, computeSeconds]);\n\n const iso = `PT${elapsed}S`;\n\n return (\n <time dateTime={iso} className={cn('tabular-nums', className)} {...props}>\n {formatElapsed(elapsed, variant)}\n </time>\n );\n}\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { useSyncExternalStore } from 'react';\n\nfunction subscribe() {\n return () => {};\n}\n\n/**\n * Returns `false` on the server and during initial client hydration, then\n * `true` once mounted — for values that are only valid client-side (e.g. the\n * viewer's actual `Intl` locale, vs. a fixed locale used for the server-\n * rendered/first-paint value) without a hydration mismatch. Implemented via\n * `useSyncExternalStore` rather than `useEffect` + `setState` — the latter\n * works, but re-derives the same \"true\" value on every mount and trips\n * `react-hooks/set-state-in-effect` since there's no actual subscription.\n */\nexport function useMounted() {\n return useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,YAAY,WAAW;;;ACFvB,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AChCA,SAAS,4BAA4B;AAErC,SAAS,YAAY;AACnB,SAAO,MAAM;AAAA,EAAC;AAChB;AAWO,SAAS,aAAa;AAC3B,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;;;AFuKI;AA1KJ,SAAS,sBAAsB,MAAY,QAAoC;AAC7E,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,SAAS,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAG5C,MAAI,SAAS,GAAG;AACd,UAAM,MAAM,KAAK,IAAI,MAAM;AAC3B,UAAMA,QAAO,KAAK,MAAM,MAAM,GAAK;AACnC,UAAMC,OAAM,KAAK,MAAMD,QAAO,EAAE;AAChC,UAAME,QAAO,KAAK,MAAMD,OAAM,EAAE;AAChC,QAAI,MAAM,IAAO,QAAO;AACxB,QAAID,QAAO,GAAI,QAAO,MAAMA,KAAI,UAAUA,UAAS,IAAI,KAAK,GAAG;AAC/D,QAAIC,OAAM,GAAI,QAAO,MAAMA,IAAG,QAAQA,SAAQ,IAAI,KAAK,GAAG;AAC1D,QAAIC,QAAO,EAAG,QAAO,MAAMA,KAAI,OAAOA,UAAS,IAAI,KAAK,GAAG;AAC3D,QAAIA,QAAO,GAAI,QAAO,MAAM,KAAK,MAAMA,QAAO,CAAC,CAAC,QAAQ,KAAK,MAAMA,QAAO,CAAC,MAAM,IAAI,KAAK,GAAG;AAC7F,WAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,MAC3C,OAAO;AAAA,MACP,KAAK;AAAA,OACD,KAAK,YAAY,MAAM,IAAI,YAAY,IAAI,EAAE,MAAM,UAAU,IAAI,CAAC,EACvE,CAAC;AAAA,EACJ;AAGA,QAAM,OAAO,KAAK,MAAM,SAAS,GAAI;AACrC,QAAM,OAAO,KAAK,MAAM,OAAO,EAAE;AACjC,QAAM,MAAM,KAAK,MAAM,OAAO,EAAE;AAChC,QAAM,OAAO,KAAK,MAAM,MAAM,EAAE;AAEhC,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,OAAO,GAAI,QAAO,GAAG,IAAI,UAAU,SAAS,IAAI,KAAK,GAAG;AAC5D,MAAI,MAAM,GAAI,QAAO,GAAG,GAAG,QAAQ,QAAQ,IAAI,KAAK,GAAG;AACvD,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,OAAO,EAAG,QAAO,GAAG,IAAI;AAC5B,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,OAAO,GAAI,QAAO,GAAG,KAAK,MAAM,OAAO,CAAC,CAAC;AAG7C,SAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,IAC3C,OAAO;AAAA,IACP,KAAK;AAAA,KACD,KAAK,YAAY,MAAM,IAAI,YAAY,IAAI,EAAE,MAAM,UAAU,IAAI,CAAC,EACvE,CAAC;AACJ;AAOA,SAAS,sBAAsB,MAAY,QAAoC;AAC7E,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,SAAS,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAG5C,MAAI,SAAS,GAAG;AACd,UAAM,MAAM,KAAK,IAAI,MAAM;AAC3B,UAAMF,QAAO,KAAK,MAAM,MAAM,GAAK;AACnC,UAAMC,OAAM,KAAK,MAAMD,QAAO,EAAE;AAChC,UAAME,QAAO,KAAK,MAAMD,OAAM,EAAE;AAChC,QAAI,MAAM,IAAO,QAAO;AACxB,QAAID,QAAO,GAAI,QAAO,MAAMA,KAAI;AAChC,QAAIC,OAAM,GAAI,QAAO,MAAMA,IAAG;AAC9B,QAAIC,QAAO,EAAG,QAAO,MAAMA,KAAI;AAC/B,QAAIA,QAAO,GAAI,QAAO,MAAM,KAAK,MAAMA,QAAO,CAAC,CAAC;AAChD,WAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,MAC3C,OAAO;AAAA,MACP,KAAK;AAAA,OACD,KAAK,YAAY,MAAM,IAAI,YAAY,IAAI,EAAE,MAAM,UAAU,IAAI,CAAC,EACvE,CAAC;AAAA,EACJ;AAGA,QAAM,OAAO,KAAK,MAAM,SAAS,GAAI;AACrC,QAAM,OAAO,KAAK,MAAM,OAAO,EAAE;AACjC,QAAM,MAAM,KAAK,MAAM,OAAO,EAAE;AAChC,QAAM,OAAO,KAAK,MAAM,MAAM,EAAE;AAEhC,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,OAAO,GAAI,QAAO,GAAG,IAAI;AAC7B,MAAI,MAAM,GAAI,QAAO,GAAG,GAAG;AAC3B,MAAI,OAAO,EAAG,QAAO,GAAG,IAAI;AAC5B,MAAI,OAAO,GAAI,QAAO,GAAG,KAAK,MAAM,OAAO,CAAC,CAAC;AAE7C,SAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,IAC3C,OAAO;AAAA,IACP,KAAK;AAAA,KACD,KAAK,YAAY,MAAM,IAAI,YAAY,IAAI,EAAE,MAAM,UAAU,IAAI,CAAC,EACvE,CAAC;AACJ;AAEA,SAAS,eAAe,MAAY,SAAgC,QAAoC;AACtG,SAAO,YAAY,YAAY,sBAAsB,MAAM,MAAM,IAAI,sBAAsB,MAAM,MAAM;AACzG;AAGA,SAAS,eAAe,MAAoB;AAC1C,QAAM,SAAS,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,QAAQ,CAAC;AACnD,QAAM,UAAU,SAAS;AACzB,MAAI,UAAU,GAAI,QAAO;AACzB,MAAI,UAAU,KAAM,QAAO;AAC3B,SAAO;AACT;AAGA,SAAS,cAAc,MAAY,QAAoC;AACrE,SAAO,KAAK,eAAe,QAAQ;AAAA,IACjC,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,cAAc;AAAA,EAChB,CAAC;AACH;AA+BO,SAAS,aAAa,IAA8E;AAA9E,eAAE,QAAM,UAAU,WAAW,OAAO,UAnKjE,IAmK6B,IAAkD,kBAAlD,IAAkD,CAAhD,QAAM,WAAqB,SAAO;AAC/D,QAAM,IAAU,cAAQ,MAAM,IAAI,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC;AACpD,QAAM,UAAU,WAAW;AAG3B,QAAM,SAAS,UAAU,SAAY;AAErC,QAAM,CAAC,OAAO,QAAQ,IAAU,eAAiB,MAAM,eAAe,GAAG,SAAS,MAAM,CAAC;AAEzF,EAAM,gBAAU,MAAM;AAGpB,aAAS,eAAe,GAAG,SAAS,MAAM,CAAC;AAE3C,UAAM,WAAW,MAAM;AACrB,YAAMC,MAAK,OAAO,YAAY,MAAM;AAClC,iBAAS,eAAe,GAAG,SAAS,MAAM,CAAC;AAAA,MAC7C,GAAG,eAAe,CAAC,CAAC;AACpB,aAAOA;AAAA,IACT;AACA,UAAM,KAAK,SAAS;AACpB,WAAO,MAAM,OAAO,cAAc,EAAE;AAAA,EACtC,GAAG,CAAC,GAAG,SAAS,MAAM,CAAC;AAEvB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU,EAAE,YAAY;AAAA,MACxB,OAAO,wBAAS,cAAc,GAAG,MAAM;AAAA,MACvC,WAAW,GAAG,gBAAgB,SAAS;AAAA,OACnC,QAJL;AAAA,MAME;AAAA;AAAA,EACH;AAEJ;AAKA,SAAS,WAAW,MAAY,SAAqC,QAAoC;AACvG,QAAM,QAAQ,IAAI,KAAK,eAAe,QAAQ,OAAO,EAAE,cAAc,IAAI;AACzE,MAAI,SAAS;AACb,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,aAAa;AAC7B,gBAAU,KAAK,MAAM,YAAY,EAAE,QAAQ,OAAO,EAAE;AAAA,IACtD,OAAO;AACL,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,eAAe,MAAY,SAAiB,KAAuB,QAAoC;AAvNhH;AAwNE,UAAQ,SAAS;AAAA,IACf,KAAK,YAAY;AACf,YAAM,UAAU,KAAK,mBAAmB,QAAQ,EAAE,SAAS,QAAQ,CAAC;AACpE,YAAM,WAAW,KAAK,mBAAmB,QAAQ,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AACpG,YAAM,WAAW,WAAW,MAAM,EAAE,MAAM,WAAW,QAAQ,UAAU,GAAG,MAAM;AAChF,YAAM,MAAK,UAAK,mBAAmB,QAAQ,EAAE,cAAc,QAAQ,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,MAA1E,YAA+E;AAC1F,aAAO,GAAG,OAAO,KAAK,QAAQ,SAAW,QAAQ,IAAI,EAAE;AAAA,IACzD;AAAA,IACA,KAAK,OAAO;AACV,YAAM,WAAW,KAAK,mBAAmB,QAAQ,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AACpG,YAAM,WAAW,WAAW,MAAM,EAAE,MAAM,WAAW,QAAQ,UAAU,GAAG,MAAM;AAChF,YAAM,MAAK,UAAK,mBAAmB,QAAQ,EAAE,cAAc,QAAQ,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,MAA1E,YAA+E;AAC1F,aAAO,GAAG,QAAQ,KAAK,QAAQ,IAAI,EAAE;AAAA,IACvC;AAAA,IACA,KAAK,SAAS;AACZ,UAAI,CAAC,IAAK,QAAO,KAAK,mBAAmB,QAAQ,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AACpG,YAAM,YAAY,KAAK,YAAY;AACnC,YAAM,UAAU,IAAI,YAAY;AAChC,UAAI,cAAc,SAAS;AACzB,cAAMC,SAAQ,KAAK,mBAAmB,QAAQ,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC;AAChF,cAAMC,UAAS,IAAI,mBAAmB,QAAQ,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AACjG,eAAO,GAAGD,MAAK,WAAWC,OAAM;AAAA,MAClC;AACA,YAAM,QAAQ,KAAK,mBAAmB,QAAQ,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AACjG,YAAM,SAAS,IAAI,mBAAmB,QAAQ,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AACjG,aAAO,GAAG,KAAK,WAAW,MAAM;AAAA,IAClC;AAAA,IACA,KAAK;AAAA,IACL;AACE,aAAO,KAAK,mBAAmB,QAAQ,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AAAA,EAC9F;AACF;AAeO,SAAS,kBAAkB,IAA8E;AAA9E,eAAE,QAAM,UAAU,QAAQ,KAAK,UAtQjE,IAsQkC,IAA6C,kBAA7C,IAA6C,CAA3C,QAAM,WAAkB,OAAK;AAC/D,QAAM,IAAU,cAAQ,MAAM,IAAI,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC;AACpD,QAAM,IAAU,cAAQ,MAAO,MAAM,IAAI,KAAK,GAAG,IAAI,QAAY,CAAC,GAAG,CAAC;AACtE,QAAM,UAAU,WAAW;AAG3B,QAAM,SAAS,UAAU,SAAY;AAErC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU,EAAE,YAAY;AAAA,MACxB,OAAO,cAAc,GAAG,MAAM;AAAA,MAC9B,WAAW,GAAG,gBAAgB,SAAS;AAAA,OACnC,QAJL;AAAA,MAME,yBAAe,GAAG,SAAS,GAAG,MAAM;AAAA;AAAA,EACvC;AAEJ;AAIA,SAAS,cAAc,cAAsB,SAAyB;AACpE,QAAM,OAAO,KAAK,MAAM,eAAe,KAAK;AAC5C,QAAM,QAAQ,KAAK,MAAO,eAAe,QAAS,IAAI;AACtD,QAAM,UAAU,KAAK,MAAO,eAAe,OAAQ,EAAE;AACrD,QAAM,UAAU,KAAK,MAAM,eAAe,EAAE;AAE5C,UAAQ,SAAS;AAAA,IACf,KAAK,YAAY;AACf,YAAM,QAAkB,CAAC;AACzB,UAAI,OAAO,EAAG,OAAM,KAAK,GAAG,IAAI,OAAO,SAAS,IAAI,KAAK,GAAG,EAAE;AAC9D,UAAI,QAAQ,EAAG,OAAM,KAAK,GAAG,KAAK,QAAQ,UAAU,IAAI,KAAK,GAAG,EAAE;AAClE,UAAI,UAAU,EAAG,OAAM,KAAK,GAAG,OAAO,UAAU,YAAY,IAAI,KAAK,GAAG,EAAE;AAC1E,UAAI,UAAU,KAAK,MAAM,WAAW,EAAG,OAAM,KAAK,GAAG,OAAO,UAAU,YAAY,IAAI,KAAK,GAAG,EAAE;AAChG,aAAO,MAAM,KAAK,IAAI;AAAA,IACxB;AAAA,IACA,KAAK,QAAQ;AACX,UAAI,OAAO,EAAG,QAAO,GAAG,IAAI,KAAK,KAAK;AACtC,UAAI,QAAQ,EAAG,QAAO,GAAG,KAAK,KAAK,OAAO;AAC1C,aAAO,GAAG,OAAO;AAAA,IACnB;AAAA,IACA,KAAK;AAAA,IACL,SAAS;AACP,UAAI,OAAO,EAAG,QAAO,GAAG,IAAI,KAAK,KAAK;AACtC,UAAI,QAAQ,EAAG,QAAO,GAAG,KAAK,KAAK,OAAO,KAAK,OAAO;AACtD,UAAI,UAAU,EAAG,QAAO,GAAG,OAAO,KAAK,OAAO;AAC9C,aAAO,GAAG,OAAO;AAAA,IACnB;AAAA,EACF;AACF;AAiBO,SAAS,YAAY,IAOP;AAPO,eAC1B;AAAA,aAAS;AAAA,IACT,UAAU;AAAA,IACV,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EA9UF,IAyU4B,IAMvB,kBANuB,IAMvB;AAAA,IALH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAGA,QAAM,YAAkB,cAAQ,MAAO,YAAY,IAAI,KAAK,SAAS,IAAI,QAAY,CAAC,SAAS,CAAC;AAEhG,QAAM,iBAAuB,kBAAY,MAAM;AAC7C,QAAI,UAAW,QAAO,KAAK,OAAO,KAAK,IAAI,IAAI,UAAU,QAAQ,KAAK,GAAI;AAC1E,WAAO,oCAAe;AAAA,EACxB,GAAG,CAAC,WAAW,WAAW,CAAC;AAE3B,QAAM,CAAC,SAAS,UAAU,IAAU,eAAS,cAAc;AAE3D,EAAM,gBAAU,MAAM;AACpB,eAAW,eAAe,CAAC;AAE3B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,UAAM,KAAK,OAAO,YAAY,MAAM;AAClC,iBAAW,eAAe,CAAC;AAAA,IAC7B,GAAG,GAAI;AACP,WAAO,MAAM,OAAO,cAAc,EAAE;AAAA,EACtC,GAAG,CAAC,MAAM,WAAW,cAAc,CAAC;AAEpC,QAAM,MAAM,KAAK,OAAO;AAExB,SACE,oBAAC,uCAAK,UAAU,KAAK,WAAW,GAAG,gBAAgB,SAAS,KAAO,QAAlE,EACE,wBAAc,SAAS,OAAO,IACjC;AAEJ;","names":["mins","hrs","days","id","start","endStr"]}
1
+ {"version":3,"sources":["../src/relative-time.tsx","../src/lib/utils.ts","../src/hooks/use-mounted.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\nimport { useMounted } from '@/hooks/use-mounted';\n\n// ── Format helpers ─────────────────────────────────────────────────────────────\n//\n// `locale` is `undefined` (browser/runtime default — the viewer's actual\n// locale, per Monarch's \"use locale-aware formatting\" content principle) once\n// mounted client-side, and a fixed `'en-US'` for the server-rendered/first-\n// paint value — the server can't know the viewer's locale ahead of time, and\n// passing a locale that differs between server and client render would\n// hydration-mismatch. Callers gate this via `useMounted()` below, so the\n// locale-aware value replaces the fixed one right after mount (see\n// RelativeTime/AbsoluteTimestamp).\n\n/** Returns a human-readable relative label for `date` vs now. */\nfunction formatRelativeDefault(date: Date, locale: string | undefined): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n\n // Future dates\n if (diffMs < 0) {\n const abs = Math.abs(diffMs);\n const mins = Math.floor(abs / 60000);\n const hrs = Math.floor(mins / 60);\n const days = Math.floor(hrs / 24);\n if (abs < 60000) return 'just now';\n if (mins < 60) return `in ${mins} minute${mins === 1 ? '' : 's'}`;\n if (hrs < 24) return `in ${hrs} hour${hrs === 1 ? '' : 's'}`;\n if (days < 7) return `in ${days} day${days === 1 ? '' : 's'}`;\n if (days < 30) return `in ${Math.floor(days / 7)} week${Math.floor(days / 7) === 1 ? '' : 's'}`;\n return `on ${date.toLocaleDateString(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n })}`;\n }\n\n // Past dates\n const secs = Math.floor(diffMs / 1000);\n const mins = Math.floor(secs / 60);\n const hrs = Math.floor(mins / 60);\n const days = Math.floor(hrs / 24);\n\n if (secs < 60) return 'just now';\n if (mins < 60) return `${mins} minute${mins === 1 ? '' : 's'} ago`;\n if (hrs < 24) return `${hrs} hour${hrs === 1 ? '' : 's'} ago`;\n if (days === 1) return 'yesterday';\n if (days < 7) return `${days} days ago`;\n if (days < 14) return 'last week';\n if (days < 30) return `${Math.floor(days / 7)} weeks ago`;\n\n // > 30 days: fall back to absolute date\n return `on ${date.toLocaleDateString(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n })}`;\n}\n\n/**\n * Compact relative label — abbreviates units for tight horizontal space\n * (tables, KPI cards). Preserves \"ago\", \"in\", \"on\", and \"just now\" so\n * directionality and reference points stay legible at a glance.\n */\nfunction formatRelativeCompact(date: Date, locale: string | undefined): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n\n // Future dates\n if (diffMs < 0) {\n const abs = Math.abs(diffMs);\n const mins = Math.floor(abs / 60000);\n const hrs = Math.floor(mins / 60);\n const days = Math.floor(hrs / 24);\n if (abs < 60000) return 'just now';\n if (mins < 60) return `in ${mins}m`;\n if (hrs < 24) return `in ${hrs}h`;\n if (days < 7) return `in ${days}d`;\n if (days < 30) return `in ${Math.floor(days / 7)}w`;\n return `on ${date.toLocaleDateString(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n })}`;\n }\n\n // Past dates\n const secs = Math.floor(diffMs / 1000);\n const mins = Math.floor(secs / 60);\n const hrs = Math.floor(mins / 60);\n const days = Math.floor(hrs / 24);\n\n if (secs < 60) return 'just now';\n if (mins < 60) return `${mins}m ago`;\n if (hrs < 24) return `${hrs}h ago`;\n if (days < 7) return `${days}d ago`;\n if (days < 30) return `${Math.floor(days / 7)}w ago`;\n\n return `on ${date.toLocaleDateString(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() ? { year: 'numeric' } : {}),\n })}`;\n}\n\nfunction formatRelative(date: Date, variant: 'default' | 'compact', locale: string | undefined): string {\n return variant === 'compact' ? formatRelativeCompact(date, locale) : formatRelativeDefault(date, locale);\n}\n\n/** Returns the update interval in ms appropriate for the current age. */\nfunction updateInterval(date: Date): number {\n const diffMs = Math.abs(Date.now() - date.getTime());\n const diffMin = diffMs / 60000;\n if (diffMin < 60) return 60_000; // update every minute while < 1 hour old\n if (diffMin < 1440) return 300_000; // every 5 min while < 1 day old\n return 3_600_000; // every hour otherwise\n}\n\n/** Formats an absolute tooltip title. */\nfunction absoluteTitle(date: Date, locale: string | undefined): string {\n return date.toLocaleString(locale, {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n timeZoneName: 'short',\n });\n}\n\n// ── Component ──────────────────────────────────────────────────────────────────\n\nexport interface RelativeTimeProps extends Omit<React.TimeHTMLAttributes<HTMLTimeElement>, 'dateTime' | 'title'> {\n /**\n * The timestamp to display. Accepts a `Date`, ISO string, or unix milliseconds.\n */\n date: Date | string | number;\n /**\n * Format variant. `default` produces full-word output (\"5 minutes ago\",\n * \"yesterday\"). `compact` abbreviates units (\"5m ago\", \"1d ago\") for tight\n * horizontal space like tables, KPI cards, or inline metadata.\n */\n variant?: 'default' | 'compact';\n /**\n * Override the tooltip shown on hover. Defaults to the full localized\n * absolute date-time string (e.g. \"Monday, January 20, 2025 at 3:22 PM PST\").\n */\n title?: string;\n}\n\n/**\n * Displays a timestamp as a live-updating relative string (\"5 minutes ago\",\n * \"yesterday\", \"on Nov 18\") with the absolute date in the native tooltip.\n *\n * Falls back to an absolute \"on [Month Day]\" format for dates older than 30 days\n * so that stale timestamps remain legible at a glance.\n *\n * @see https://design.upbound.io/components/date-and-time\n */\nexport function RelativeTime({ date, variant = 'default', title, className, ...props }: RelativeTimeProps) {\n const d = React.useMemo(() => new Date(date), [date]);\n const mounted = useMounted();\n // Fixed locale for the server-rendered/first-paint value (the server can't\n // know the viewer's locale); the viewer's actual locale once mounted.\n const locale = mounted ? undefined : 'en-US';\n\n const [label, setLabel] = React.useState<string>(() => formatRelative(d, variant, locale));\n\n React.useEffect(() => {\n // Re-compute immediately on mount (picks up the viewer's real locale, and\n // avoids the relative label going stale)\n setLabel(formatRelative(d, variant, locale));\n\n const schedule = () => {\n const id = window.setInterval(() => {\n setLabel(formatRelative(d, variant, locale));\n }, updateInterval(d));\n return id;\n };\n const id = schedule();\n return () => window.clearInterval(id);\n }, [d, variant, locale]);\n\n return (\n <time\n dateTime={d.toISOString()}\n title={title ?? absoluteTitle(d, locale)}\n className={cn('tabular-nums', className)}\n {...props}\n >\n {label}\n </time>\n );\n}\n\n// ── Absolute Timestamp ────────────────────────────────────────────────────────\n\n/** Formats am/pm per Content Principles: lowercase, space before, no periods. */\nfunction formatAmPm(date: Date, options: Intl.DateTimeFormatOptions, locale: string | undefined): string {\n const parts = new Intl.DateTimeFormat(locale, options).formatToParts(date);\n let result = '';\n for (const part of parts) {\n if (part.type === 'dayPeriod') {\n result += part.value.toLowerCase().replace(/\\./g, '');\n } else {\n result += part.value;\n }\n }\n return result;\n}\n\nfunction formatAbsolute(date: Date, variant: string, end: Date | undefined, locale: string | undefined): string {\n switch (variant) {\n case 'deadline': {\n const weekday = date.toLocaleDateString(locale, { weekday: 'short' });\n const datePart = date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n const timePart = formatAmPm(date, { hour: 'numeric', minute: '2-digit' }, locale);\n const tz = date.toLocaleTimeString(locale, { timeZoneName: 'short' }).split(' ').pop() ?? '';\n return `${weekday}, ${datePart} \\u00b7 ${timePart} ${tz}`;\n }\n case 'log': {\n const datePart = date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n const timePart = formatAmPm(date, { hour: 'numeric', minute: '2-digit' }, locale);\n const tz = date.toLocaleTimeString(locale, { timeZoneName: 'short' }).split(' ').pop() ?? '';\n return `${datePart}, ${timePart} ${tz}`;\n }\n case 'range': {\n if (!end) return date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n const startYear = date.getFullYear();\n const endYear = end.getFullYear();\n if (startYear === endYear) {\n const start = date.toLocaleDateString(locale, { month: 'short', day: 'numeric' });\n const endStr = end.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n return `${start} \\u2013 ${endStr}`;\n }\n const start = date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n const endStr = end.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n return `${start} \\u2013 ${endStr}`;\n }\n case 'date':\n default:\n return date.toLocaleDateString(locale, { month: 'short', day: 'numeric', year: 'numeric' });\n }\n}\n\nexport interface AbsoluteTimestampProps extends Omit<React.TimeHTMLAttributes<HTMLTimeElement>, 'dateTime'> {\n /** The timestamp to display. */\n date: Date | string | number;\n /** Format variant matching the Content Principles absolute timestamp table. */\n variant?: 'deadline' | 'log' | 'date' | 'range';\n /** End date for range variant. */\n end?: Date | string | number;\n}\n\n/**\n * Formats a date as an absolute timestamp following the Content Principles.\n * Use for deadlines, certificate expiry, audit logs, and date-only displays.\n */\nexport function AbsoluteTimestamp({ date, variant = 'date', end, className, ...props }: AbsoluteTimestampProps) {\n const d = React.useMemo(() => new Date(date), [date]);\n const e = React.useMemo(() => (end ? new Date(end) : undefined), [end]);\n const mounted = useMounted();\n // Fixed locale for the server-rendered/first-paint value (the server can't\n // know the viewer's locale); the viewer's actual locale once mounted.\n const locale = mounted ? undefined : 'en-US';\n\n return (\n <time\n dateTime={d.toISOString()}\n title={absoluteTitle(d, locale)}\n className={cn('tabular-nums', className)}\n {...props}\n >\n {formatAbsolute(d, variant, e, locale)}\n </time>\n );\n}\n\n// ── Elapsed Time ──────────────────────────────────────────────────────────────\n\nfunction formatElapsed(totalSeconds: number, variant: string): string {\n const days = Math.floor(totalSeconds / 86400);\n const hours = Math.floor((totalSeconds % 86400) / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = Math.floor(totalSeconds % 60);\n\n switch (variant) {\n case 'expanded': {\n const parts: string[] = [];\n if (days > 0) parts.push(`${days} day${days === 1 ? '' : 's'}`);\n if (hours > 0) parts.push(`${hours} hour${hours === 1 ? '' : 's'}`);\n if (minutes > 0) parts.push(`${minutes} minute${minutes === 1 ? '' : 's'}`);\n if (seconds > 0 || parts.length === 0) parts.push(`${seconds} second${seconds === 1 ? '' : 's'}`);\n return parts.join(', ');\n }\n case 'long': {\n if (days > 0) return `${days}d ${hours}h`;\n if (hours > 0) return `${hours}h ${minutes}m`;\n return `${minutes}m`;\n }\n case 'compact':\n default: {\n if (days > 0) return `${days}d ${hours}h`;\n if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;\n if (minutes > 0) return `${minutes}m ${seconds}s`;\n return `${seconds}s`;\n }\n }\n}\n\nexport interface ElapsedTimeProps extends Omit<React.TimeHTMLAttributes<HTMLTimeElement>, 'dateTime'> {\n /** Total elapsed seconds. Ignored if startedAt is provided. */\n seconds?: number;\n /** Format variant matching the Content Principles elapsed time table. */\n variant?: 'compact' | 'expanded' | 'long';\n /** Live-tick every second for active operations. */\n live?: boolean;\n /** Compute elapsed from a start time instead of a fixed seconds value. */\n startedAt?: Date | string | number;\n}\n\n/**\n * Formats a duration as elapsed time following the Content Principles.\n * Use for reconciliation loops, build jobs, health checks, and running operations.\n */\nexport function ElapsedTime({\n seconds: secondsProp,\n variant = 'compact',\n live = false,\n startedAt,\n className,\n ...props\n}: ElapsedTimeProps) {\n const startDate = React.useMemo(() => (startedAt ? new Date(startedAt) : undefined), [startedAt]);\n\n const computeSeconds = React.useCallback(() => {\n if (startDate) return Math.floor((Date.now() - startDate.getTime()) / 1000);\n return secondsProp ?? 0;\n }, [startDate, secondsProp]);\n\n const [elapsed, setElapsed] = React.useState(computeSeconds);\n\n React.useEffect(() => {\n setElapsed(computeSeconds());\n\n if (!live && !startDate) return;\n\n const id = window.setInterval(() => {\n setElapsed(computeSeconds());\n }, 1000);\n return () => window.clearInterval(id);\n }, [live, startDate, computeSeconds]);\n\n const iso = `PT${elapsed}S`;\n\n return (\n <time dateTime={iso} className={cn('tabular-nums', className)} {...props}>\n {formatElapsed(elapsed, variant)}\n </time>\n );\n}\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport function sortBy<T>(items: T[], getKey: (item: T) => string): T[] {\n return [...items].sort((a, b) => getKey(a).localeCompare(getKey(b)));\n}\n","import { useSyncExternalStore } from 'react';\n\nfunction subscribe() {\n return () => {};\n}\n\n/**\n * Returns `false` on the server and during initial client hydration, then\n * `true` once mounted — for values that are only valid client-side (e.g. the\n * viewer's actual `Intl` locale, vs. a fixed locale used for the server-\n * rendered/first-paint value) without a hydration mismatch. Implemented via\n * `useSyncExternalStore` rather than `useEffect` + `setState` — the latter\n * works, but re-derives the same \"true\" value on every mount and trips\n * `react-hooks/set-state-in-effect` since there's no actual subscription.\n */\nexport function useMounted() {\n return useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n );\n}\n"],"mappings":"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","names":["mins","hrs","days","id","start","endStr"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/utils.ts","../src/section-header.tsx"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { cn } from '@/lib/utils';\n\nfunction SectionHeader({ className, children, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"section-header\"\n className={cn('flex w-full items-start justify-between gap-4', className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nfunction SectionHeaderContent({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"section-header-content\" className={cn('flex flex-col gap-1', className)} {...props} />;\n}\n\nfunction SectionHeaderTitle({ className, ...props }: React.ComponentProps<'h2'>) {\n return <h2 data-slot=\"section-header-title\" className={cn('text-h3 text-foreground', className)} {...props} />;\n}\n\nfunction SectionHeaderDescription({ className, ...props }: React.ComponentProps<'p'>) {\n return (\n <p data-slot=\"section-header-description\" className={cn('text-body text-muted-foreground', className)} {...props} />\n );\n}\n\nfunction SectionHeaderMeta({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"section-header-meta\"\n className={cn(\n 'text-body text-muted-foreground flex flex-wrap items-center gap-4',\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-(--icon-default)\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction SectionHeaderActions({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"section-header-actions\" className={cn('flex items-center gap-2', className)} {...props} />;\n}\n\nfunction SectionHeaderTabs({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"section-header-tabs\" className={cn('border-b', className)} {...props} />;\n}\n\nexport {\n SectionHeader,\n SectionHeaderContent,\n SectionHeaderTitle,\n SectionHeaderDescription,\n SectionHeaderMeta,\n SectionHeaderActions,\n SectionHeaderTabs,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AC5BI;AAFJ,SAAS,cAAc,IAAgE;AAAhE,eAAE,aAAW,SAFpC,IAEuB,IAA0B,kBAA1B,IAA0B,CAAxB,aAAW;AAClC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,iDAAiD,SAAS;AAAA,OACpE,QAHL;AAAA,MAKE;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,qBAAqB,IAAsD;AAAtD,eAAE,YAdhC,IAc8B,IAAgB,kBAAhB,IAAgB,CAAd;AAC9B,SAAO,oBAAC,wBAAI,aAAU,0BAAyB,WAAW,GAAG,uBAAuB,SAAS,KAAO,MAAO;AAC7G;AAEA,SAAS,mBAAmB,IAAqD;AAArD,eAAE,YAlB9B,IAkB4B,IAAgB,kBAAhB,IAAgB,CAAd;AAC5B,SAAO,oBAAC,uBAAG,aAAU,wBAAuB,WAAW,GAAG,2BAA2B,SAAS,KAAO,MAAO;AAC9G;AAEA,SAAS,yBAAyB,IAAoD;AAApD,eAAE,YAtBpC,IAsBkC,IAAgB,kBAAhB,IAAgB,CAAd;AAClC,SACE,oBAAC,sBAAE,aAAU,8BAA6B,WAAW,GAAG,mCAAmC,SAAS,KAAO,MAAO;AAEtH;AAEA,SAAS,kBAAkB,IAAsD;AAAtD,eAAE,YA5B7B,IA4B2B,IAAgB,kBAAhB,IAAgB,CAAd;AAC3B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,OACI;AAAA,EACN;AAEJ;AAEA,SAAS,qBAAqB,IAAsD;AAAtD,eAAE,YA1ChC,IA0C8B,IAAgB,kBAAhB,IAAgB,CAAd;AAC9B,SAAO,oBAAC,wBAAI,aAAU,0BAAyB,WAAW,GAAG,2BAA2B,SAAS,KAAO,MAAO;AACjH;AAEA,SAAS,kBAAkB,IAAsD;AAAtD,eAAE,YA9C7B,IA8C2B,IAAgB,kBAAhB,IAAgB,CAAd;AAC3B,SAAO,oBAAC,wBAAI,aAAU,uBAAsB,WAAW,GAAG,YAAY,SAAS,KAAO,MAAO;AAC/F;","names":[]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/section-header.tsx"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport function sortBy<T>(items: T[], getKey: (item: T) => string): T[] {\n return [...items].sort((a, b) => getKey(a).localeCompare(getKey(b)));\n}\n","import { cn } from '@/lib/utils';\n\nfunction SectionHeader({ className, children, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"section-header\"\n className={cn('flex w-full items-start justify-between gap-4', className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nfunction SectionHeaderContent({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"section-header-content\" className={cn('flex flex-col gap-1', className)} {...props} />;\n}\n\nfunction SectionHeaderTitle({ className, ...props }: React.ComponentProps<'h2'>) {\n return <h2 data-slot=\"section-header-title\" className={cn('text-h3 text-foreground', className)} {...props} />;\n}\n\nfunction SectionHeaderDescription({ className, ...props }: React.ComponentProps<'p'>) {\n return (\n <p data-slot=\"section-header-description\" className={cn('text-body text-muted-foreground', className)} {...props} />\n );\n}\n\nfunction SectionHeaderMeta({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"section-header-meta\"\n className={cn(\n 'text-body text-muted-foreground flex flex-wrap items-center gap-4',\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-(--icon-default)\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction SectionHeaderActions({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"section-header-actions\" className={cn('flex items-center gap-2', className)} {...props} />;\n}\n\nfunction SectionHeaderTabs({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"section-header-tabs\" className={cn('border-b', className)} {...props} />;\n}\n\nexport {\n SectionHeader,\n SectionHeaderContent,\n SectionHeaderTitle,\n SectionHeaderDescription,\n SectionHeaderMeta,\n SectionHeaderActions,\n SectionHeaderTabs,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AC5BI;AAFJ,SAAS,cAAc,IAAgE;AAAhE,eAAE,aAAW,SAFpC,IAEuB,IAA0B,kBAA1B,IAA0B,CAAxB,aAAW;AAClC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,iDAAiD,SAAS;AAAA,OACpE,QAHL;AAAA,MAKE;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,qBAAqB,IAAsD;AAAtD,eAAE,YAdhC,IAc8B,IAAgB,kBAAhB,IAAgB,CAAd;AAC9B,SAAO,oBAAC,wBAAI,aAAU,0BAAyB,WAAW,GAAG,uBAAuB,SAAS,KAAO,MAAO;AAC7G;AAEA,SAAS,mBAAmB,IAAqD;AAArD,eAAE,YAlB9B,IAkB4B,IAAgB,kBAAhB,IAAgB,CAAd;AAC5B,SAAO,oBAAC,uBAAG,aAAU,wBAAuB,WAAW,GAAG,2BAA2B,SAAS,KAAO,MAAO;AAC9G;AAEA,SAAS,yBAAyB,IAAoD;AAApD,eAAE,YAtBpC,IAsBkC,IAAgB,kBAAhB,IAAgB,CAAd;AAClC,SACE,oBAAC,sBAAE,aAAU,8BAA6B,WAAW,GAAG,mCAAmC,SAAS,KAAO,MAAO;AAEtH;AAEA,SAAS,kBAAkB,IAAsD;AAAtD,eAAE,YA5B7B,IA4B2B,IAAgB,kBAAhB,IAAgB,CAAd;AAC3B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,OACI;AAAA,EACN;AAEJ;AAEA,SAAS,qBAAqB,IAAsD;AAAtD,eAAE,YA1ChC,IA0C8B,IAAgB,kBAAhB,IAAgB,CAAd;AAC9B,SAAO,oBAAC,wBAAI,aAAU,0BAAyB,WAAW,GAAG,2BAA2B,SAAS,KAAO,MAAO;AACjH;AAEA,SAAS,kBAAkB,IAAsD;AAAtD,eAAE,YA9C7B,IA8C2B,IAAgB,kBAAhB,IAAgB,CAAd;AAC3B,SAAO,oBAAC,wBAAI,aAAU,uBAAsB,WAAW,GAAG,YAAY,SAAS,KAAO,MAAO;AAC/F;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/section-nav.tsx","../src/lib/utils.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Slot } from 'radix-ui';\n\nimport { cn } from '@/lib/utils';\n\n/**\n * SectionNav — vertical navigation for in-page section routing.\n *\n * Distinct from `Sidebar`: Sidebar is the app-level chrome (org switcher,\n * primary nav, user menu, mobile drawer). SectionNav is a context-free\n * navigation list that lives inside a page or section — settings sub-nav,\n * resource detail tabs (route-based), profile sub-pages, etc.\n *\n * Distinct from `Tabs (vertical orientation)`: Tabs swap views within a\n * single route (UI state); SectionNav navigates between routes (URL changes,\n * `aria-current=\"page\"` on the active item).\n *\n * Composition:\n *\n * <SectionNav>\n * <SectionNavList>\n * <SectionNavItem href=\"/settings\" isActive>Account</SectionNavItem>\n * <SectionNavItem href=\"/settings/notifications\">\n * Notifications\n * </SectionNavItem>\n * </SectionNavList>\n * </SectionNav>\n *\n * Wrap with Next `<Link>` via `asChild`:\n *\n * <SectionNavItem asChild isActive>\n * <Link href=\"/settings\">Account</Link>\n * </SectionNavItem>\n */\n\n// ── Root ──────────────────────────────────────────────\n\nfunction SectionNav({ className, ...props }: React.ComponentProps<'nav'>) {\n return <nav data-slot=\"section-nav\" className={cn('flex flex-col gap-4', className)} {...props} />;\n}\n\n// ── List ──────────────────────────────────────────────\n\nfunction SectionNavList({ className, ...props }: React.ComponentProps<'ul'>) {\n return <ul data-slot=\"section-nav-list\" className={cn('flex flex-col gap-px', className)} {...props} />;\n}\n\n// ── Group (heading + list pair) ───────────────────────\n\nfunction SectionNavGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"section-nav-group\" className={cn('flex flex-col gap-2', className)} {...props} />;\n}\n\nfunction SectionNavGroupLabel({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"section-nav-group-label\"\n className={cn('text-caption text-muted-foreground px-3 font-medium tracking-wide uppercase', className)}\n {...props}\n />\n );\n}\n\n// ── Item ──────────────────────────────────────────────\n\ninterface SectionNavItemProps extends React.ComponentProps<'a'> {\n /**\n * Marks the item as the current page. Applies active styling and sets\n * `aria-current=\"page\"`. Active state is fully controlled — wire to your\n * router's pathname match.\n */\n isActive?: boolean;\n asChild?: boolean;\n}\n\nfunction SectionNavItem({ className, isActive, asChild, children, ...props }: SectionNavItemProps) {\n const Comp = asChild ? Slot.Root : 'a';\n return (\n <li data-slot=\"section-nav-item\">\n <Comp\n data-active={isActive || undefined}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n \"group/section-nav-item text-body text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground data-[active=true]:bg-accent data-[active=true]:text-accent-foreground flex w-full items-center gap-2 rounded-md px-3 py-1.5 font-medium outline-hidden motion-safe:transition-colors [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-(--icon-default) [&_svg:not([class*='size-'])]:w-(--icon-default)!\",\n className,\n )}\n {...props}\n >\n {children}\n </Comp>\n </li>\n );\n}\n\n// ── Item description (for rich items with label + sub-text) ────\n\nfunction SectionNavItemDescription({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"section-nav-item-description\"\n className={cn(\n 'text-body-sm text-muted-foreground group-hover/section-nav-item:text-accent-foreground/80 group-data-[active=true]/section-nav-item:text-accent-foreground/80 block font-normal',\n className,\n )}\n {...props}\n />\n );\n}\n\n// ── Sub navigation (nested under an item) ─────────────\n\nfunction SectionNavSub({ className, ...props }: React.ComponentProps<'ul'>) {\n return (\n <ul\n data-slot=\"section-nav-sub\"\n className={cn('border-border mt-1 ml-7 flex flex-col gap-px border-l pl-2', className)}\n {...props}\n />\n );\n}\n\nexport {\n SectionNav,\n SectionNavList,\n SectionNavGroup,\n SectionNavGroupLabel,\n SectionNavItem,\n SectionNavItemDescription,\n SectionNavSub,\n};\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,SAAS,YAAY;;;ACHrB,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;ADQS;AADT,SAAS,WAAW,IAAsD;AAAtD,eAAE,YAvCtB,IAuCoB,IAAgB,kBAAhB,IAAgB,CAAd;AACpB,SAAO,oBAAC,wBAAI,aAAU,eAAc,WAAW,GAAG,uBAAuB,SAAS,KAAO,MAAO;AAClG;AAIA,SAAS,eAAe,IAAqD;AAArD,eAAE,YA7C1B,IA6CwB,IAAgB,kBAAhB,IAAgB,CAAd;AACxB,SAAO,oBAAC,uBAAG,aAAU,oBAAmB,WAAW,GAAG,wBAAwB,SAAS,KAAO,MAAO;AACvG;AAIA,SAAS,gBAAgB,IAAsD;AAAtD,eAAE,YAnD3B,IAmDyB,IAAgB,kBAAhB,IAAgB,CAAd;AACzB,SAAO,oBAAC,wBAAI,aAAU,qBAAoB,WAAW,GAAG,uBAAuB,SAAS,KAAO,MAAO;AACxG;AAEA,SAAS,qBAAqB,IAAsD;AAAtD,eAAE,YAvDhC,IAuD8B,IAAgB,kBAAhB,IAAgB,CAAd;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,+EAA+E,SAAS;AAAA,OAClG;AAAA,EACN;AAEJ;AAcA,SAAS,eAAe,IAA2E;AAA3E,eAAE,aAAW,UAAU,SAAS,SA7ExD,IA6EwB,IAA6C,kBAA7C,IAA6C,CAA3C,aAAW,YAAU,WAAS;AACtD,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE,oBAAC,QAAG,aAAU,oBACZ;AAAA,IAAC;AAAA;AAAA,MACC,eAAa,YAAY;AAAA,MACzB,gBAAc,WAAW,SAAS;AAAA,MAClC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,OACI,QAPL;AAAA,MASE;AAAA;AAAA,EACH,GACF;AAEJ;AAIA,SAAS,0BAA0B,IAAuD;AAAvD,eAAE,YAlGrC,IAkGmC,IAAgB,kBAAhB,IAAgB,CAAd;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,OACI;AAAA,EACN;AAEJ;AAIA,SAAS,cAAc,IAAqD;AAArD,eAAE,YAjHzB,IAiHuB,IAAgB,kBAAhB,IAAgB,CAAd;AACvB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,8DAA8D,SAAS;AAAA,OACjF;AAAA,EACN;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/section-nav.tsx","../src/lib/utils.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Slot } from 'radix-ui';\n\nimport { cn } from '@/lib/utils';\n\n/**\n * SectionNav — vertical navigation for in-page section routing.\n *\n * Distinct from `Sidebar`: Sidebar is the app-level chrome (org switcher,\n * primary nav, user menu, mobile drawer). SectionNav is a context-free\n * navigation list that lives inside a page or section — settings sub-nav,\n * resource detail tabs (route-based), profile sub-pages, etc.\n *\n * Distinct from `Tabs (vertical orientation)`: Tabs swap views within a\n * single route (UI state); SectionNav navigates between routes (URL changes,\n * `aria-current=\"page\"` on the active item).\n *\n * Composition:\n *\n * <SectionNav>\n * <SectionNavList>\n * <SectionNavItem href=\"/settings\" isActive>Account</SectionNavItem>\n * <SectionNavItem href=\"/settings/notifications\">\n * Notifications\n * </SectionNavItem>\n * </SectionNavList>\n * </SectionNav>\n *\n * Wrap with Next `<Link>` via `asChild`:\n *\n * <SectionNavItem asChild isActive>\n * <Link href=\"/settings\">Account</Link>\n * </SectionNavItem>\n */\n\n// ── Root ──────────────────────────────────────────────\n\nfunction SectionNav({ className, ...props }: React.ComponentProps<'nav'>) {\n return <nav data-slot=\"section-nav\" className={cn('flex flex-col gap-4', className)} {...props} />;\n}\n\n// ── List ──────────────────────────────────────────────\n\nfunction SectionNavList({ className, ...props }: React.ComponentProps<'ul'>) {\n return <ul data-slot=\"section-nav-list\" className={cn('flex flex-col gap-px', className)} {...props} />;\n}\n\n// ── Group (heading + list pair) ───────────────────────\n\nfunction SectionNavGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"section-nav-group\" className={cn('flex flex-col gap-2', className)} {...props} />;\n}\n\nfunction SectionNavGroupLabel({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"section-nav-group-label\"\n className={cn('text-caption text-muted-foreground px-3 font-medium tracking-wide uppercase', className)}\n {...props}\n />\n );\n}\n\n// ── Item ──────────────────────────────────────────────\n\ninterface SectionNavItemProps extends React.ComponentProps<'a'> {\n /**\n * Marks the item as the current page. Applies active styling and sets\n * `aria-current=\"page\"`. Active state is fully controlled — wire to your\n * router's pathname match.\n */\n isActive?: boolean;\n asChild?: boolean;\n}\n\nfunction SectionNavItem({ className, isActive, asChild, children, ...props }: SectionNavItemProps) {\n const Comp = asChild ? Slot.Root : 'a';\n return (\n <li data-slot=\"section-nav-item\">\n <Comp\n data-active={isActive || undefined}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n \"group/section-nav-item text-body text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground data-[active=true]:bg-accent data-[active=true]:text-accent-foreground flex w-full items-center gap-2 rounded-md px-3 py-1.5 font-medium outline-hidden motion-safe:transition-colors [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-(--icon-default) [&_svg:not([class*='size-'])]:w-(--icon-default)!\",\n className,\n )}\n {...props}\n >\n {children}\n </Comp>\n </li>\n );\n}\n\n// ── Item description (for rich items with label + sub-text) ────\n\nfunction SectionNavItemDescription({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"section-nav-item-description\"\n className={cn(\n 'text-body-sm text-muted-foreground group-hover/section-nav-item:text-accent-foreground/80 group-data-[active=true]/section-nav-item:text-accent-foreground/80 block font-normal',\n className,\n )}\n {...props}\n />\n );\n}\n\n// ── Sub navigation (nested under an item) ─────────────\n\nfunction SectionNavSub({ className, ...props }: React.ComponentProps<'ul'>) {\n return (\n <ul\n data-slot=\"section-nav-sub\"\n className={cn('border-border mt-1 ml-7 flex flex-col gap-px border-l pl-2', className)}\n {...props}\n />\n );\n}\n\nexport {\n SectionNav,\n SectionNavList,\n SectionNavGroup,\n SectionNavGroupLabel,\n SectionNavItem,\n SectionNavItemDescription,\n SectionNavSub,\n};\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport function sortBy<T>(items: T[], getKey: (item: T) => string): T[] {\n return [...items].sort((a, b) => getKey(a).localeCompare(getKey(b)));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,SAAS,YAAY;;;ACHrB,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;ADQS;AADT,SAAS,WAAW,IAAsD;AAAtD,eAAE,YAvCtB,IAuCoB,IAAgB,kBAAhB,IAAgB,CAAd;AACpB,SAAO,oBAAC,wBAAI,aAAU,eAAc,WAAW,GAAG,uBAAuB,SAAS,KAAO,MAAO;AAClG;AAIA,SAAS,eAAe,IAAqD;AAArD,eAAE,YA7C1B,IA6CwB,IAAgB,kBAAhB,IAAgB,CAAd;AACxB,SAAO,oBAAC,uBAAG,aAAU,oBAAmB,WAAW,GAAG,wBAAwB,SAAS,KAAO,MAAO;AACvG;AAIA,SAAS,gBAAgB,IAAsD;AAAtD,eAAE,YAnD3B,IAmDyB,IAAgB,kBAAhB,IAAgB,CAAd;AACzB,SAAO,oBAAC,wBAAI,aAAU,qBAAoB,WAAW,GAAG,uBAAuB,SAAS,KAAO,MAAO;AACxG;AAEA,SAAS,qBAAqB,IAAsD;AAAtD,eAAE,YAvDhC,IAuD8B,IAAgB,kBAAhB,IAAgB,CAAd;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,+EAA+E,SAAS;AAAA,OAClG;AAAA,EACN;AAEJ;AAcA,SAAS,eAAe,IAA2E;AAA3E,eAAE,aAAW,UAAU,SAAS,SA7ExD,IA6EwB,IAA6C,kBAA7C,IAA6C,CAA3C,aAAW,YAAU,WAAS;AACtD,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE,oBAAC,QAAG,aAAU,oBACZ;AAAA,IAAC;AAAA;AAAA,MACC,eAAa,YAAY;AAAA,MACzB,gBAAc,WAAW,SAAS;AAAA,MAClC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,OACI,QAPL;AAAA,MASE;AAAA;AAAA,EACH,GACF;AAEJ;AAIA,SAAS,0BAA0B,IAAuD;AAAvD,eAAE,YAlGrC,IAkGmC,IAAgB,kBAAhB,IAAgB,CAAd;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,OACI;AAAA,EACN;AAEJ;AAIA,SAAS,cAAc,IAAqD;AAArD,eAAE,YAjHzB,IAiHuB,IAAgB,kBAAhB,IAAgB,CAAd;AACvB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,8DAA8D,SAAS;AAAA,OACjF;AAAA,EACN;AAEJ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/utils.ts","../src/timeline.tsx"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import * as React from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Icon } from '@upbound/monarch-core';\nimport { Item, ItemGroup } from '@upbound/monarch-core';\n\nfunction Timeline({ className, ...props }: React.ComponentProps<typeof ItemGroup>) {\n return <ItemGroup data-slot=\"timeline\" className={cn(className)} {...props} />;\n}\n\nfunction TimelineItem({ className, children, ...props }: React.ComponentProps<typeof Item>) {\n return (\n <Item data-slot=\"timeline-item\" className={cn('group/timeline-item gap-3 py-4', className)} {...props}>\n <div className=\"relative flex flex-col items-center self-stretch\">\n <Icon name=\"circle-dot\" size=\"sm\" className=\"text-primary shrink-0\" />\n <span\n aria-hidden=\"true\"\n className=\"bg-timeline-connector absolute top-5 w-px group-last/timeline-item:hidden\"\n style={{ bottom: '-1rem' }}\n />\n </div>\n {children}\n </Item>\n );\n}\n\nexport { Timeline, TimelineItem };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AC7BA,SAAS,YAAY;AACrB,SAAS,MAAM,iBAAiB;AAGvB,cAMH,YANG;AADT,SAAS,SAAS,IAAiE;AAAjE,eAAE,YANpB,IAMkB,IAAgB,kBAAhB,IAAgB,CAAd;AAClB,SAAO,oBAAC,4BAAU,aAAU,YAAW,WAAW,GAAG,SAAS,KAAO,MAAO;AAC9E;AAEA,SAAS,aAAa,IAAsE;AAAtE,eAAE,aAAW,SAVnC,IAUsB,IAA0B,kBAA1B,IAA0B,CAAxB,aAAW;AACjC,SACE,qBAAC,qCAAK,aAAU,iBAAgB,WAAW,GAAG,kCAAkC,SAAS,KAAO,QAA/F,EACC;AAAA,yBAAC,SAAI,WAAU,oDACb;AAAA,0BAAC,QAAK,MAAK,cAAa,MAAK,MAAK,WAAU,yBAAwB;AAAA,MACpE;AAAA,QAAC;AAAA;AAAA,UACC,eAAY;AAAA,UACZ,WAAU;AAAA,UACV,OAAO,EAAE,QAAQ,QAAQ;AAAA;AAAA,MAC3B;AAAA,OACF;AAAA,IACC;AAAA,MACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/timeline.tsx"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport function sortBy<T>(items: T[], getKey: (item: T) => string): T[] {\n return [...items].sort((a, b) => getKey(a).localeCompare(getKey(b)));\n}\n","import * as React from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Icon } from '@upbound/monarch-core';\nimport { Item, ItemGroup } from '@upbound/monarch-core';\n\nfunction Timeline({ className, ...props }: React.ComponentProps<typeof ItemGroup>) {\n return <ItemGroup data-slot=\"timeline\" className={cn(className)} {...props} />;\n}\n\nfunction TimelineItem({ className, children, ...props }: React.ComponentProps<typeof Item>) {\n return (\n <Item data-slot=\"timeline-item\" className={cn('group/timeline-item gap-3 py-4', className)} {...props}>\n <div className=\"relative flex flex-col items-center self-stretch\">\n <Icon name=\"circle-dot\" size=\"sm\" className=\"text-primary shrink-0\" />\n <span\n aria-hidden=\"true\"\n className=\"bg-timeline-connector absolute top-5 w-px group-last/timeline-item:hidden\"\n style={{ bottom: '-1rem' }}\n />\n </div>\n {children}\n </Item>\n );\n}\n\nexport { Timeline, TimelineItem };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEM,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AC7BA,SAAS,YAAY;AACrB,SAAS,MAAM,iBAAiB;AAGvB,cAMH,YANG;AADT,SAAS,SAAS,IAAiE;AAAjE,eAAE,YANpB,IAMkB,IAAgB,kBAAhB,IAAgB,CAAd;AAClB,SAAO,oBAAC,4BAAU,aAAU,YAAW,WAAW,GAAG,SAAS,KAAO,MAAO;AAC9E;AAEA,SAAS,aAAa,IAAsE;AAAtE,eAAE,aAAW,SAVnC,IAUsB,IAA0B,kBAA1B,IAA0B,CAAxB,aAAW;AACjC,SACE,qBAAC,qCAAK,aAAU,iBAAgB,WAAW,GAAG,kCAAkC,SAAS,KAAO,QAA/F,EACC;AAAA,yBAAC,SAAI,WAAU,oDACb;AAAA,0BAAC,QAAK,MAAK,cAAa,MAAK,MAAK,WAAU,yBAAwB;AAAA,MACpE;AAAA,QAAC;AAAA;AAAA,UACC,eAAY;AAAA,UACZ,WAAU;AAAA,UACV,OAAO,EAAE,QAAQ,QAAQ;AAAA;AAAA,MAC3B;AAAA,OACF;AAAA,IACC;AAAA,MACH;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upbound/monarch-blocks",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "Upbound's design system — composed components.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -9,7 +9,9 @@
9
9
  "directory": "packages/monarch-blocks"
10
10
  },
11
11
  "type": "module",
12
- "sideEffects": false,
12
+ "sideEffects": [
13
+ "**/*.css"
14
+ ],
13
15
  "files": [
14
16
  "dist"
15
17
  ],
@@ -26,6 +28,7 @@
26
28
  "import": "./dist/*.js",
27
29
  "default": "./dist/*.js"
28
30
  },
31
+ "./graph.css": "./dist/graph.css",
29
32
  "./package.json": "./package.json"
30
33
  },
31
34
  "scripts": {
@@ -44,11 +47,12 @@
44
47
  "tailwindcss": "^4.0.0"
45
48
  },
46
49
  "dependencies": {
47
- "@upbound/monarch-core": "^0.5.0",
50
+ "@upbound/monarch-core": "^0.7.0",
48
51
  "@tanstack/react-table": "^8.21.3",
49
52
  "clsx": "^2.1.1",
50
53
  "radix-ui": "^1.4.3",
51
54
  "react-day-picker": "^10.0.1",
55
+ "reactflow": "11.11.4",
52
56
  "recharts": "^3.8.0",
53
57
  "tailwind-merge": "^3.5.0"
54
58
  },