@hexclave/dashboard-ui-components 1.0.0 → 1.0.1
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.
- package/dist/components/alert.js +4 -4
- package/dist/components/alert.js.map +1 -1
- package/dist/components/analytics-chart/analytics-chart-pie.js +33 -11
- package/dist/components/analytics-chart/analytics-chart-pie.js.map +1 -1
- package/dist/components/analytics-chart/analytics-chart.js +3 -3
- package/dist/components/analytics-chart/analytics-chart.js.map +1 -1
- package/dist/components/analytics-chart/default-analytics-chart-tooltip.js +4 -4
- package/dist/components/analytics-chart/default-analytics-chart-tooltip.js.map +1 -1
- package/dist/components/analytics-chart/types.d.ts +1 -0
- package/dist/components/analytics-chart/types.d.ts.map +1 -1
- package/dist/components/analytics-chart/types.js.map +1 -1
- package/dist/components/badge.js +2 -2
- package/dist/components/badge.js.map +1 -1
- package/dist/components/button.js +11 -11
- package/dist/components/button.js.map +1 -1
- package/dist/components/card.js +7 -7
- package/dist/components/card.js.map +1 -1
- package/dist/components/chart-card.js +3 -3
- package/dist/components/chart-card.js.map +1 -1
- package/dist/components/chart-container.js +2 -2
- package/dist/components/chart-container.js.map +1 -1
- package/dist/components/chart-legend.js +3 -3
- package/dist/components/chart-legend.js.map +1 -1
- package/dist/components/chart-tooltip.js +7 -7
- package/dist/components/chart-tooltip.js.map +1 -1
- package/dist/components/data-grid/data-grid-toolbar.js +7 -7
- package/dist/components/data-grid/data-grid-toolbar.js.map +1 -1
- package/dist/components/data-grid/data-grid.js +16 -16
- package/dist/components/data-grid/data-grid.js.map +1 -1
- package/dist/components/data-grid/state.js +2 -2
- package/dist/components/data-grid/state.js.map +1 -1
- package/dist/components/dialog.js +22 -22
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/empty-state.js +2 -2
- package/dist/components/empty-state.js.map +1 -1
- package/dist/components/input.js +8 -8
- package/dist/components/input.js.map +1 -1
- package/dist/components/metric-card.js +5 -5
- package/dist/components/metric-card.js.map +1 -1
- package/dist/components/pill-toggle.js +11 -10
- package/dist/components/pill-toggle.js.map +1 -1
- package/dist/components/progress-bar.js +4 -4
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/separator.js +2 -2
- package/dist/components/separator.js.map +1 -1
- package/dist/components/skeleton.js +2 -2
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/table.js +14 -14
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.js +10 -10
- package/dist/components/tabs.js.map +1 -1
- package/dist/dashboard-ui-components.global.js +1647 -1605
- package/dist/dashboard-ui-components.global.js.map +4 -4
- package/dist/esm/components/alert.js.map +1 -1
- package/dist/esm/components/analytics-chart/analytics-chart-pie.js +33 -11
- package/dist/esm/components/analytics-chart/analytics-chart-pie.js.map +1 -1
- package/dist/esm/components/analytics-chart/analytics-chart.js.map +1 -1
- package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.js.map +1 -1
- package/dist/esm/components/analytics-chart/types.d.ts +1 -0
- package/dist/esm/components/analytics-chart/types.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/types.js.map +1 -1
- package/dist/esm/components/badge.js.map +1 -1
- package/dist/esm/components/button.js.map +1 -1
- package/dist/esm/components/card.js.map +1 -1
- package/dist/esm/components/chart-card.js.map +1 -1
- package/dist/esm/components/chart-container.js.map +1 -1
- package/dist/esm/components/chart-legend.js.map +1 -1
- package/dist/esm/components/chart-tooltip.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid-toolbar.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.js.map +1 -1
- package/dist/esm/components/data-grid/state.js.map +1 -1
- package/dist/esm/components/dialog.js.map +1 -1
- package/dist/esm/components/empty-state.js.map +1 -1
- package/dist/esm/components/input.js.map +1 -1
- package/dist/esm/components/metric-card.js.map +1 -1
- package/dist/esm/components/pill-toggle.js +1 -0
- package/dist/esm/components/pill-toggle.js.map +1 -1
- package/dist/esm/components/progress-bar.js.map +1 -1
- package/dist/esm/components/separator.js.map +1 -1
- package/dist/esm/components/skeleton.js.map +1 -1
- package/dist/esm/components/table.js.map +1 -1
- package/dist/esm/components/tabs.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-analytics-chart-tooltip.js","names":[],"sources":["../../../../src/components/analytics-chart/default-analytics-chart-tooltip.tsx"],"sourcesContent":["import { cn } from \"@stackframe/stack-ui\";\nimport {\n ArrowDownIcon,\n ArrowUpIcon,\n CursorClickIcon,\n MinusIcon,\n PushPinSimpleIcon,\n} from \"@phosphor-icons/react\";\nimport type { CSSProperties } from \"react\";\nimport type { AnalyticsChartStrings } from \"./strings\";\nimport type { AnalyticsChartDelta, Point } from \"./types\";\n\n/** Trend pill — small rounded badge with an up/down/flat arrow, a signed\n * percentage, and an optional trailing label. Shared between the default\n * tooltip, the pie view, and the demo panels (which re-export it). */\nexport function TrendPill({\n delta,\n label,\n size = \"sm\",\n}: {\n delta: AnalyticsChartDelta,\n label?: string,\n size?: \"sm\" | \"md\",\n}) {\n const { pct, sign } = delta;\n const tone =\n sign === \"up\" ? \"text-emerald-600 dark:text-emerald-400 bg-emerald-500/10\"\n : sign === \"down\" ? \"text-rose-600 dark:text-rose-400 bg-rose-500/10\"\n : \"text-muted-foreground bg-foreground/[0.06]\";\n const Icon = sign === \"up\" ? ArrowUpIcon : sign === \"down\" ? ArrowDownIcon : MinusIcon;\n const text = pct == null ? \"—\" : `${pct > 0 ? \"+\" : \"\"}${pct}%`;\n return (\n <span className={cn(\n \"inline-flex items-center gap-1 rounded-full font-mono tabular-nums font-medium\",\n size === \"md\" ? \"px-2 py-0.5 text-[11px]\" : \"px-1.5 py-[1px] text-[10px]\",\n tone,\n )}>\n <Icon weight=\"bold\" className={size === \"md\" ? \"size-3\" : \"size-2.5\"} aria-hidden=\"true\" />\n {text}\n {label && <span className=\"ml-0.5 text-muted-foreground font-normal\">{label}</span>}\n </span>\n );\n}\n\nexport type AnalyticsChartTooltipSegmentRow = {\n key: string,\n label: string,\n value: number,\n /** Light-theme color for the dot / swatch. */\n color: string,\n /** Dark-theme color for the dot / swatch. */\n colorDark: string,\n};\n\nexport type AnalyticsChartTooltipLayerView = {\n /** Stable layer id (e.g. `\"signups\"`, `\"previous\"`). */\n id: string,\n /** Consumer-provided layer label. */\n label: string,\n /** Resolved layer color (light theme). */\n color: string,\n /** Resolved layer color (dark theme). */\n colorDark: string,\n /** Flat total for this layer at the hovered index. Populated regardless\n * of segmentation so consumers can render the same number in either mode. */\n total: number,\n /** True iff this layer is rendered as a stacked breakdown. */\n segmented: boolean,\n /** Per-segment rows — empty when `segmented === false`. Order matches\n * `segmentSeries`. */\n segments: AnalyticsChartTooltipSegmentRow[],\n};\n\nexport type AnalyticsChartTooltipContext = {\n /** Index into the visible window. */\n activeIndex: number,\n /** Raw point at `activeIndex` — convenient for `.ts` access. */\n point: Point,\n /** True when the tooltip is pinned (via click) and stable under hover. */\n isPinned: boolean,\n /** Primary layer view or null when the primary layer is hidden. */\n primary: AnalyticsChartTooltipLayerView | null,\n /** Compare layer view or null when the compare layer is hidden. */\n compare: AnalyticsChartTooltipLayerView | null,\n /** Flat-mode delta between primary and compare totals. Null when either\n * side is hidden. Consumers should feed this into their trend pill. */\n delta: AnalyticsChartDelta | null,\n /** Pre-bound value formatter for y-axis values. */\n formatValue: (v: number) => string,\n /** Pre-bound formatter for x-axis values. */\n formatDate: (ts: number) => string,\n /** Resolved strings — already merged with defaults. */\n strings: AnalyticsChartStrings,\n};\n\nexport type DefaultAnalyticsChartTooltipProps = {\n ctx: AnalyticsChartTooltipContext,\n};\n\n/** The default tooltip body. The tooltip is rendered as an\n * absolutely-positioned sibling of `<ChartContainer>`, which means it sits\n * OUTSIDE the `[data-chart=…]` subtree that scopes shadcn's `--color-${key}`\n * CSS variables. We therefore cannot reference those variables for segment\n * swatches — instead, every swatch uses a single span with `--c-l`/`--c-d`\n * custom properties + Tailwind arbitrary variants so one DOM element covers\n * both themes. */\nexport function DefaultAnalyticsChartTooltip({ ctx }: DefaultAnalyticsChartTooltipProps) {\n const { point, isPinned, primary, compare, delta, formatValue: fv, formatDate: fd, strings } = ctx;\n const anySegmented = (primary?.segmented ?? false) || (compare?.segmented ?? false);\n return (\n <div className=\"rounded-xl border border-foreground/10 bg-background/95 px-3 py-2.5 shadow-[0_10px_28px_rgba(15,23,42,0.18)] backdrop-blur-xl dark:shadow-[0_10px_28px_rgba(0,0,0,0.55)] min-w-[180px]\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-mono text-[10px] uppercase tracking-wider text-muted-foreground\">\n {fd(point.ts)}\n </span>\n {isPinned && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-blue-500/10 px-1.5 py-[1px] text-[9px] font-semibold uppercase tracking-wider text-blue-600 dark:text-blue-300\">\n <PushPinSimpleIcon weight=\"fill\" className=\"size-2.5\" aria-hidden=\"true\" />\n {strings.pinnedBadge}\n </span>\n )}\n </div>\n <div className=\"mt-2 flex flex-col gap-1.5\">\n <TooltipLayerRows view={primary} keyPrefix=\"p\" fv={fv} muted={false} />\n <TooltipLayerRows view={compare} keyPrefix=\"c\" fv={fv} muted />\n </div>\n {anySegmented && (\n <div className=\"mt-2 flex flex-col gap-1 border-t border-foreground/[0.07] pt-2\">\n {primary?.segmented && (\n <LayerSummaryRow\n label={`${primary.label}${strings.layerTotalSuffix}`}\n value={fv(primary.total)}\n muted={false}\n />\n )}\n {compare?.segmented && (\n <LayerSummaryRow\n label={`${compare.label}${strings.layerTotalSuffix}`}\n value={fv(compare.total)}\n muted\n />\n )}\n {primary?.segmented && compare?.segmented && delta && (\n <div className=\"mt-1 flex items-center justify-between\">\n <span className=\"font-mono text-[10px] uppercase tracking-wider text-muted-foreground\">\n {strings.deltaVsPrev}\n </span>\n <TrendPill delta={delta} size=\"sm\" />\n </div>\n )}\n </div>\n )}\n {!anySegmented && delta && primary && compare && (\n <div className=\"mt-2 flex items-center justify-between border-t border-foreground/[0.07] pt-2\">\n <span className=\"font-mono text-[10px] uppercase tracking-wider text-muted-foreground\">\n {strings.deltaVsPrev}\n </span>\n <TrendPill delta={delta} size=\"sm\" />\n </div>\n )}\n <div className=\"mt-2 flex items-center gap-1 text-[10px] text-muted-foreground\">\n <CursorClickIcon weight=\"bold\" className=\"size-2.5\" aria-hidden=\"true\" />\n <span>{isPinned ? strings.hintClickAnywhereUnpin : strings.hintClickToPin}</span>\n </div>\n </div>\n );\n}\n\n/** Render either a single flat row or the per-segment breakdown rows for\n * one tooltip layer view. Collapses what were formerly two parallel\n * primary/compare branches into one component. */\nfunction TooltipLayerRows({\n view,\n keyPrefix,\n fv,\n muted,\n}: {\n view: AnalyticsChartTooltipLayerView | null,\n keyPrefix: string,\n fv: (v: number) => string,\n muted: boolean,\n}) {\n if (!view) return null;\n if (!view.segmented) {\n return (\n <LayerTotalRow\n light={view.color}\n dark={view.colorDark}\n label={view.label}\n value={fv(view.total)}\n muted={muted}\n />\n );\n }\n return (\n <>\n {view.segments.map((s) => (\n <LayerTotalRow\n key={`${keyPrefix}-${s.key}`}\n light={s.color}\n dark={s.colorDark}\n label={s.label}\n value={fv(s.value)}\n muted={muted}\n />\n ))}\n </>\n );\n}\n\n/** Single row: swatch + label + value. One DOM element for the swatch —\n * dark-mode color is picked up via `--c-d`. */\nfunction LayerTotalRow({\n light,\n dark,\n label,\n value,\n muted,\n}: {\n light: string,\n dark: string,\n label: string,\n value: string,\n muted: boolean,\n}) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <span\n className=\"size-2 rounded-full bg-[var(--c-l)] dark:bg-[var(--c-d)]\"\n style={{ \"--c-l\": light, \"--c-d\": dark } as CSSProperties}\n />\n <span className=\"text-[11px] text-muted-foreground\">{label}</span>\n <span className={cn(\n \"ml-auto font-mono text-xs tabular-nums\",\n muted ? \"text-muted-foreground\" : \"font-semibold text-foreground\",\n )}>\n {value}\n </span>\n </div>\n );\n}\n\nfunction LayerSummaryRow({\n label,\n value,\n muted,\n}: {\n label: string,\n value: string,\n muted: boolean,\n}) {\n return (\n <div className=\"flex items-center justify-between\">\n <span className=\"font-mono text-[10px] uppercase tracking-wider text-muted-foreground\">\n {label}\n </span>\n <span className={cn(\n \"font-mono text-xs tabular-nums\",\n muted ? \"text-muted-foreground\" : \"font-semibold text-foreground\",\n )}>\n {value}\n </span>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"default-analytics-chart-tooltip.js","names":[],"sources":["../../../../src/components/analytics-chart/default-analytics-chart-tooltip.tsx"],"sourcesContent":["import { cn } from \"@hexclave/ui\";\nimport {\n ArrowDownIcon,\n ArrowUpIcon,\n CursorClickIcon,\n MinusIcon,\n PushPinSimpleIcon,\n} from \"@phosphor-icons/react\";\nimport type { CSSProperties } from \"react\";\nimport type { AnalyticsChartStrings } from \"./strings\";\nimport type { AnalyticsChartDelta, Point } from \"./types\";\n\n/** Trend pill — small rounded badge with an up/down/flat arrow, a signed\n * percentage, and an optional trailing label. Shared between the default\n * tooltip, the pie view, and the demo panels (which re-export it). */\nexport function TrendPill({\n delta,\n label,\n size = \"sm\",\n}: {\n delta: AnalyticsChartDelta,\n label?: string,\n size?: \"sm\" | \"md\",\n}) {\n const { pct, sign } = delta;\n const tone =\n sign === \"up\" ? \"text-emerald-600 dark:text-emerald-400 bg-emerald-500/10\"\n : sign === \"down\" ? \"text-rose-600 dark:text-rose-400 bg-rose-500/10\"\n : \"text-muted-foreground bg-foreground/[0.06]\";\n const Icon = sign === \"up\" ? ArrowUpIcon : sign === \"down\" ? ArrowDownIcon : MinusIcon;\n const text = pct == null ? \"—\" : `${pct > 0 ? \"+\" : \"\"}${pct}%`;\n return (\n <span className={cn(\n \"inline-flex items-center gap-1 rounded-full font-mono tabular-nums font-medium\",\n size === \"md\" ? \"px-2 py-0.5 text-[11px]\" : \"px-1.5 py-[1px] text-[10px]\",\n tone,\n )}>\n <Icon weight=\"bold\" className={size === \"md\" ? \"size-3\" : \"size-2.5\"} aria-hidden=\"true\" />\n {text}\n {label && <span className=\"ml-0.5 text-muted-foreground font-normal\">{label}</span>}\n </span>\n );\n}\n\nexport type AnalyticsChartTooltipSegmentRow = {\n key: string,\n label: string,\n value: number,\n /** Light-theme color for the dot / swatch. */\n color: string,\n /** Dark-theme color for the dot / swatch. */\n colorDark: string,\n};\n\nexport type AnalyticsChartTooltipLayerView = {\n /** Stable layer id (e.g. `\"signups\"`, `\"previous\"`). */\n id: string,\n /** Consumer-provided layer label. */\n label: string,\n /** Resolved layer color (light theme). */\n color: string,\n /** Resolved layer color (dark theme). */\n colorDark: string,\n /** Flat total for this layer at the hovered index. Populated regardless\n * of segmentation so consumers can render the same number in either mode. */\n total: number,\n /** True iff this layer is rendered as a stacked breakdown. */\n segmented: boolean,\n /** Per-segment rows — empty when `segmented === false`. Order matches\n * `segmentSeries`. */\n segments: AnalyticsChartTooltipSegmentRow[],\n};\n\nexport type AnalyticsChartTooltipContext = {\n /** Index into the visible window. */\n activeIndex: number,\n /** Raw point at `activeIndex` — convenient for `.ts` access. */\n point: Point,\n /** True when the tooltip is pinned (via click) and stable under hover. */\n isPinned: boolean,\n /** Primary layer view or null when the primary layer is hidden. */\n primary: AnalyticsChartTooltipLayerView | null,\n /** Compare layer view or null when the compare layer is hidden. */\n compare: AnalyticsChartTooltipLayerView | null,\n /** Flat-mode delta between primary and compare totals. Null when either\n * side is hidden. Consumers should feed this into their trend pill. */\n delta: AnalyticsChartDelta | null,\n /** Pre-bound value formatter for y-axis values. */\n formatValue: (v: number) => string,\n /** Pre-bound formatter for x-axis values. */\n formatDate: (ts: number) => string,\n /** Resolved strings — already merged with defaults. */\n strings: AnalyticsChartStrings,\n};\n\nexport type DefaultAnalyticsChartTooltipProps = {\n ctx: AnalyticsChartTooltipContext,\n};\n\n/** The default tooltip body. The tooltip is rendered as an\n * absolutely-positioned sibling of `<ChartContainer>`, which means it sits\n * OUTSIDE the `[data-chart=…]` subtree that scopes shadcn's `--color-${key}`\n * CSS variables. We therefore cannot reference those variables for segment\n * swatches — instead, every swatch uses a single span with `--c-l`/`--c-d`\n * custom properties + Tailwind arbitrary variants so one DOM element covers\n * both themes. */\nexport function DefaultAnalyticsChartTooltip({ ctx }: DefaultAnalyticsChartTooltipProps) {\n const { point, isPinned, primary, compare, delta, formatValue: fv, formatDate: fd, strings } = ctx;\n const anySegmented = (primary?.segmented ?? false) || (compare?.segmented ?? false);\n return (\n <div className=\"rounded-xl border border-foreground/10 bg-background/95 px-3 py-2.5 shadow-[0_10px_28px_rgba(15,23,42,0.18)] backdrop-blur-xl dark:shadow-[0_10px_28px_rgba(0,0,0,0.55)] min-w-[180px]\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-mono text-[10px] uppercase tracking-wider text-muted-foreground\">\n {fd(point.ts)}\n </span>\n {isPinned && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-blue-500/10 px-1.5 py-[1px] text-[9px] font-semibold uppercase tracking-wider text-blue-600 dark:text-blue-300\">\n <PushPinSimpleIcon weight=\"fill\" className=\"size-2.5\" aria-hidden=\"true\" />\n {strings.pinnedBadge}\n </span>\n )}\n </div>\n <div className=\"mt-2 flex flex-col gap-1.5\">\n <TooltipLayerRows view={primary} keyPrefix=\"p\" fv={fv} muted={false} />\n <TooltipLayerRows view={compare} keyPrefix=\"c\" fv={fv} muted />\n </div>\n {anySegmented && (\n <div className=\"mt-2 flex flex-col gap-1 border-t border-foreground/[0.07] pt-2\">\n {primary?.segmented && (\n <LayerSummaryRow\n label={`${primary.label}${strings.layerTotalSuffix}`}\n value={fv(primary.total)}\n muted={false}\n />\n )}\n {compare?.segmented && (\n <LayerSummaryRow\n label={`${compare.label}${strings.layerTotalSuffix}`}\n value={fv(compare.total)}\n muted\n />\n )}\n {primary?.segmented && compare?.segmented && delta && (\n <div className=\"mt-1 flex items-center justify-between\">\n <span className=\"font-mono text-[10px] uppercase tracking-wider text-muted-foreground\">\n {strings.deltaVsPrev}\n </span>\n <TrendPill delta={delta} size=\"sm\" />\n </div>\n )}\n </div>\n )}\n {!anySegmented && delta && primary && compare && (\n <div className=\"mt-2 flex items-center justify-between border-t border-foreground/[0.07] pt-2\">\n <span className=\"font-mono text-[10px] uppercase tracking-wider text-muted-foreground\">\n {strings.deltaVsPrev}\n </span>\n <TrendPill delta={delta} size=\"sm\" />\n </div>\n )}\n <div className=\"mt-2 flex items-center gap-1 text-[10px] text-muted-foreground\">\n <CursorClickIcon weight=\"bold\" className=\"size-2.5\" aria-hidden=\"true\" />\n <span>{isPinned ? strings.hintClickAnywhereUnpin : strings.hintClickToPin}</span>\n </div>\n </div>\n );\n}\n\n/** Render either a single flat row or the per-segment breakdown rows for\n * one tooltip layer view. Collapses what were formerly two parallel\n * primary/compare branches into one component. */\nfunction TooltipLayerRows({\n view,\n keyPrefix,\n fv,\n muted,\n}: {\n view: AnalyticsChartTooltipLayerView | null,\n keyPrefix: string,\n fv: (v: number) => string,\n muted: boolean,\n}) {\n if (!view) return null;\n if (!view.segmented) {\n return (\n <LayerTotalRow\n light={view.color}\n dark={view.colorDark}\n label={view.label}\n value={fv(view.total)}\n muted={muted}\n />\n );\n }\n return (\n <>\n {view.segments.map((s) => (\n <LayerTotalRow\n key={`${keyPrefix}-${s.key}`}\n light={s.color}\n dark={s.colorDark}\n label={s.label}\n value={fv(s.value)}\n muted={muted}\n />\n ))}\n </>\n );\n}\n\n/** Single row: swatch + label + value. One DOM element for the swatch —\n * dark-mode color is picked up via `--c-d`. */\nfunction LayerTotalRow({\n light,\n dark,\n label,\n value,\n muted,\n}: {\n light: string,\n dark: string,\n label: string,\n value: string,\n muted: boolean,\n}) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <span\n className=\"size-2 rounded-full bg-[var(--c-l)] dark:bg-[var(--c-d)]\"\n style={{ \"--c-l\": light, \"--c-d\": dark } as CSSProperties}\n />\n <span className=\"text-[11px] text-muted-foreground\">{label}</span>\n <span className={cn(\n \"ml-auto font-mono text-xs tabular-nums\",\n muted ? \"text-muted-foreground\" : \"font-semibold text-foreground\",\n )}>\n {value}\n </span>\n </div>\n );\n}\n\nfunction LayerSummaryRow({\n label,\n value,\n muted,\n}: {\n label: string,\n value: string,\n muted: boolean,\n}) {\n return (\n <div className=\"flex items-center justify-between\">\n <span className=\"font-mono text-[10px] uppercase tracking-wider text-muted-foreground\">\n {label}\n </span>\n <span className={cn(\n \"font-mono text-xs tabular-nums\",\n muted ? \"text-muted-foreground\" : \"font-semibold text-foreground\",\n )}>\n {value}\n </span>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../../src/components/analytics-chart/types.ts"],"mappings":";;KACY,KAAA;EACV,EAAA;EACA,MAAA,EAAQ,MAAA;AAAA;;iBAIM,UAAA,CAAW,CAAA,EAAG,KAAA,EAAO,EAAA;;;;AAArC;iBASgB,QAAA,CAAS,GAAA;AAAA,KAOb,UAAA;EACV,KAAA;EACA,KAAA;EACA,WAAA;AAAA;;KAIU,oBAAA;EACV,GAAA;EACA,KAAA;AAAA;AAAA,KAGU,cAAA;AAAA,KAQA,iBAAA;EACV,IAAA,aArBoB;EAuBpB,MAAA,WAvBoB;EAyBpB,QAAA;AAAA;AAAA,KAEU,eAAA;EACV,IAAA,WAzBW;EA2BX,SAAA;EACA,MAAA;AAAA;AAAA,KAEU,kBAAA;EACV,IAAA,cAtBU;EAwBV,QAAA;EAEA,OAAA;EACA,MAAA;AAAA;AAAA,KAEU,kBAAA;EACV,IAAA,cAtB2B;EAwB3B,IAAA,2BArBA;EAuBA,QAAA;AAAA;AAAA,KAEU,kBAAA;EACV,IAAA,cAtByB;EAwBzB,KAAA;EACA,MAAA;AAAA;AAAA,KAEU,iBAAA;EACV,IAAA;EAxBM;;AAER;;;EA4BE,MAAA,mCA3BA;EA6BA,QAAA;AAAA;AAAA,KAGU,UAAA,GACR,iBAAA,GACA,eAAA,GACA,kBAAA,GACA,kBAAA,GACA,kBAAA,GACA,iBAAA;AAAA,KAEQ,kBAAA;AAAA,KACA,uBAAA;AAAA,KACA,yBAAA;AAAA,KAEP,6BAAA;EACH,EAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA;EACA,KAAA;EACA,SAAA;EAtCQ;AAEV;;EAwCE,QAAA;EAxC4B;;EA2C5B,aAAA,YAAyB,oBAAA;EAvCzB;;;AAEF;EA0CE,mBAAA;AAAA;AAAA,KAEU,uBAAA,GAA0B,6BAAA;EACpC,IAAA;EACA,WAAA,EAAa,yBAAA;AAAA;AAAA,KAEH,uBAAA,GAA0B,6BAAA;EACpC,IAAA;EACA,WAAA,EAAa,yBAAA;EACb,WAAA;AAAA;AAAA,KAEU,sBAAA,GAAyB,6BAAA;EACnC,IAAA;EACA,WAAA;AAAA;AAAA,KAGU,uBAAA,GACR,uBAAA,GACA,uBAAA,GACA,sBAAA;AAAA,KAEQ,8BAAA;EACV,EAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA;EACA,KAAA;AAAA;AAAA,KAGU,mBAAA,GACR,uBAAA,GACA,8BAAA;AAAA,KAEQ,oBAAA,YAAgC,mBAAA;AAAA,KAEhC,6BAAA;EACV,IAAA;EACA,MAAA,EAAQ,oBAAA,EA3DoB;EA6D5B,WAAA,EAAa,UAAA,EA7De;EA+D5B,WAAA,EAAa,UAAA;EACb,QAAA;EACA,SAAA;EACA,SAAA;EACA,SAAA;EACA,WAAA;AAAA;AAAA,KAEU,sBAAA;EACV,IAAA;EACA,MAAA,EAAQ,oBAAA;EACR,WAAA,EAAa,UAAA;EACb,WAAA,EAAa,UAAA;AAAA;AAAA,KAEH,mBAAA,GACR,6BAAA,GACA,sBAAA;AAAA,KAEQ,mBAAA;EACV,GAAA;EACA,IAAA;AAAA;;;;KAMU,sBAAA;EACV,WAAA;EACA,WAAA;EACA,kBAAA;EACA,kBAAA;EACA,SAAA;AAAA;AAAA,KAGU,yBAAA;EAER,IAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../../src/components/analytics-chart/types.ts"],"mappings":";;KACY,KAAA;EACV,EAAA;EACA,MAAA,EAAQ,MAAA;AAAA;;iBAIM,UAAA,CAAW,CAAA,EAAG,KAAA,EAAO,EAAA;;;;AAArC;iBASgB,QAAA,CAAS,GAAA;AAAA,KAOb,UAAA;EACV,KAAA;EACA,KAAA;EACA,WAAA;AAAA;;KAIU,oBAAA;EACV,GAAA;EACA,KAAA;AAAA;AAAA,KAGU,cAAA;AAAA,KAQA,iBAAA;EACV,IAAA,aArBoB;EAuBpB,MAAA,WAvBoB;EAyBpB,QAAA;AAAA;AAAA,KAEU,eAAA;EACV,IAAA,WAzBW;EA2BX,SAAA;EACA,MAAA;AAAA;AAAA,KAEU,kBAAA;EACV,IAAA,cAtBU;EAwBV,QAAA;EAEA,OAAA;EACA,MAAA;AAAA;AAAA,KAEU,kBAAA;EACV,IAAA,cAtB2B;EAwB3B,IAAA,2BArBA;EAuBA,QAAA;AAAA;AAAA,KAEU,kBAAA;EACV,IAAA,cAtByB;EAwBzB,KAAA;EACA,MAAA;AAAA;AAAA,KAEU,iBAAA;EACV,IAAA;EAxBM;;AAER;;;EA4BE,MAAA,mCA3BA;EA6BA,QAAA;AAAA;AAAA,KAGU,UAAA,GACR,iBAAA,GACA,eAAA,GACA,kBAAA,GACA,kBAAA,GACA,kBAAA,GACA,iBAAA;AAAA,KAEQ,kBAAA;AAAA,KACA,uBAAA;AAAA,KACA,yBAAA;AAAA,KAEP,6BAAA;EACH,EAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA;EACA,KAAA;EACA,SAAA;EAtCQ;AAEV;;EAwCE,QAAA;EAxC4B;;EA2C5B,aAAA,YAAyB,oBAAA;EAvCzB;;;AAEF;EA0CE,mBAAA;AAAA;AAAA,KAEU,uBAAA,GAA0B,6BAAA;EACpC,IAAA;EACA,WAAA,EAAa,yBAAA;AAAA;AAAA,KAEH,uBAAA,GAA0B,6BAAA;EACpC,IAAA;EACA,WAAA,EAAa,yBAAA;EACb,WAAA;AAAA;AAAA,KAEU,sBAAA,GAAyB,6BAAA;EACnC,IAAA;EACA,WAAA;AAAA;AAAA,KAGU,uBAAA,GACR,uBAAA,GACA,uBAAA,GACA,sBAAA;AAAA,KAEQ,8BAAA;EACV,EAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA;EACA,KAAA;AAAA;AAAA,KAGU,mBAAA,GACR,uBAAA,GACA,8BAAA;AAAA,KAEQ,oBAAA,YAAgC,mBAAA;AAAA,KAEhC,6BAAA;EACV,IAAA;EACA,MAAA,EAAQ,oBAAA,EA3DoB;EA6D5B,WAAA,EAAa,UAAA,EA7De;EA+D5B,WAAA,EAAa,UAAA;EACb,QAAA;EACA,SAAA;EACA,SAAA;EACA,SAAA;EACA,WAAA;AAAA;AAAA,KAEU,sBAAA;EACV,IAAA;EACA,MAAA,EAAQ,oBAAA;EACR,WAAA,EAAa,UAAA;EACb,WAAA,EAAa,UAAA;AAAA;AAAA,KAEH,mBAAA,GACR,6BAAA,GACA,sBAAA;AAAA,KAEQ,mBAAA;EACV,GAAA;EACA,IAAA;AAAA;;;;KAMU,sBAAA;EACV,WAAA;EACA,WAAA;EACA,kBAAA;EACA,kBAAA;EACA,SAAA;EACA,aAAA;AAAA;AAAA,KAGU,yBAAA;EAER,IAAA,gBA3EkC;EA6ElC,GAAA,UA3EF;EA6EE,GAAA,UA7EoC;EA+EpC,eAAA,oBA7EQ;EA+ER,cAAA;AAAA;EAGA,IAAA,cAlFkC;EAoFlC,KAAA,qBAlFF;EAoFE,IAAA;AAAA;AAAA,KAGQ,qBAAA;EAtFC,8DAwFX,OAAA,EAAS,yBAAA,EAtFuB;EAwFhC,OAAA,EAAS,yBAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/components/analytics-chart/types.ts"],"sourcesContent":["/** Time-series point. `values` is keyed by layer id. */\nexport type Point = {\n ts: number,\n values: Record<string, number>,\n};\n\n/** Missing or non-finite values become 0. */\nexport function pointValue(p: Point, id: string): number {\n const v = p.values[id];\n return typeof v === \"number\" && Number.isFinite(v) ? v : 0;\n}\n\n/** Sanitize a string into a valid CSS `<ident>` token.\n * Replaces characters not allowed in CSS identifiers (like `$`, spaces,\n * slashes, dots) with underscores. Used to build safe `var(--color-xxx)`\n * custom property names from arbitrary segment keys. */\nexport function cssIdent(raw: string): string {\n // Replace everything that isn't a letter, digit, hyphen, or underscore.\n // Prefix with `_` if the result starts with a digit (not valid as ident start).\n const cleaned = raw.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return /^\\d/.test(cleaned) ? `_${cleaned}` : cleaned;\n}\n\nexport type Annotation = {\n index: number,\n label: string,\n description: string,\n};\n\n/** Breakdown category definition — `{ key, label }` tuple. */\nexport type AnalyticsChartSeries = {\n key: string,\n label: string,\n};\n\nexport type FormatKindType =\n | \"numeric\"\n | \"short\"\n | \"currency\"\n | \"duration\"\n | \"datetime\"\n | \"percent\";\n\nexport type FormatKindNumeric = {\n type: \"numeric\",\n /** Locale used for grouping and digit separators. Defaults to \"en-US\". */\n locale?: string,\n /** Fixed decimal places (0-4). Defaults to 0. */\n decimals?: number,\n};\nexport type FormatKindShort = {\n type: \"short\",\n /** Decimal places after the unit suffix (1.2K vs 1.20K). Defaults to 1. */\n precision?: number,\n locale?: string,\n};\nexport type FormatKindCurrency = {\n type: \"currency\",\n /** ISO 4217 code. Defaults to \"USD\". */\n currency?: string,\n /** Divisor applied before formatting — e.g. 100 for cents → dollars. Defaults to 1. */\n divisor?: number,\n locale?: string,\n};\nexport type FormatKindDuration = {\n type: \"duration\",\n /** Source unit of the input value. Defaults to \"s\". */\n unit?: \"ms\" | \"s\" | \"m\" | \"h\",\n /** Show the smallest unit even when zero. Defaults to false. */\n showZero?: boolean,\n};\nexport type FormatKindDatetime = {\n type: \"datetime\",\n /** Render style. Defaults to \"short\". */\n style?: \"short\" | \"long\" | \"iso\" | \"relative\",\n locale?: string,\n};\nexport type FormatKindPercent = {\n type: \"percent\",\n /** How to interpret the input value:\n * - \"fraction\" → 0..1 → multiply by 100 (default)\n * - \"basis\" → 0..10000 → divide by 100\n * - \"whole\" → 0..100 → no scaling\n */\n source?: \"fraction\" | \"basis\" | \"whole\",\n /** Decimal places. Defaults to 1. */\n decimals?: number,\n};\n\nexport type FormatKind =\n | FormatKindNumeric\n | FormatKindShort\n | FormatKindCurrency\n | FormatKindDuration\n | FormatKindDatetime\n | FormatKindPercent;\n\nexport type AnalyticsChartView = \"timeseries\" | \"pie\";\nexport type AnalyticsChartLayerType = \"line\" | \"area\" | \"bar\";\nexport type AnalyticsChartStrokeStyle = \"solid\" | \"dashed\" | \"dotted\";\n\ntype AnalyticsChartDataLayerCommon = {\n id: string,\n kind: \"primary\" | \"compare\",\n label: string,\n visible: boolean,\n color: string,\n segmented: boolean,\n /** Per-day per-category values. Outer index is the day (matches the\n * chart data array index); inner index is the category (matches\n * `segmentSeries`). Rows should sum to `point.values[layer.id]`. */\n segments?: readonly (readonly number[])[],\n /** Breakdown category definitions ordered to match the inner index of\n * `segments`. */\n segmentSeries?: readonly AnalyticsChartSeries[],\n /** Absolute index into the full data array at which this layer's values\n * become \"in progress\" (incomplete and still changing). Points from this\n * index onward render with a dashed overlay so users don't panic at a\n * half-filled bucket. Applies to line and area rendering only. */\n inProgressFromIndex?: number | null,\n};\nexport type AnalyticsChartLineLayer = AnalyticsChartDataLayerCommon & {\n type: \"line\",\n strokeStyle: AnalyticsChartStrokeStyle,\n};\nexport type AnalyticsChartAreaLayer = AnalyticsChartDataLayerCommon & {\n type: \"area\",\n strokeStyle: AnalyticsChartStrokeStyle,\n fillOpacity: number,\n};\nexport type AnalyticsChartBarLayer = AnalyticsChartDataLayerCommon & {\n type: \"bar\",\n fillOpacity: number,\n};\n\nexport type AnalyticsChartDataLayer =\n | AnalyticsChartLineLayer\n | AnalyticsChartAreaLayer\n | AnalyticsChartBarLayer;\n\nexport type AnalyticsChartAnnotationsLayer = {\n id: string,\n kind: \"annotations\",\n label: string,\n visible: boolean,\n color: string,\n};\n\nexport type AnalyticsChartLayer =\n | AnalyticsChartDataLayer\n | AnalyticsChartAnnotationsLayer;\n\nexport type AnalyticsChartLayers = readonly AnalyticsChartLayer[];\n\nexport type AnalyticsChartTimeseriesState = {\n view: \"timeseries\",\n layers: AnalyticsChartLayers,\n /** Format applied to every x-axis value. Defaults to `datetime / short`. */\n xFormatKind: FormatKind,\n /** Format applied to every y-axis value. Defaults to `short`. */\n yFormatKind: FormatKind,\n showGrid: boolean,\n showXAxis: boolean,\n showYAxis: boolean,\n zoomRange: [number, number] | null,\n pinnedIndex: number | null,\n};\nexport type AnalyticsChartPieState = {\n view: \"pie\",\n layers: AnalyticsChartLayers,\n xFormatKind: FormatKind,\n yFormatKind: FormatKind,\n};\nexport type AnalyticsChartState =\n | AnalyticsChartTimeseriesState\n | AnalyticsChartPieState;\n\nexport type AnalyticsChartDelta = {\n pct: number | null,\n sign: \"up\" | \"down\" | \"flat\" | \"na\",\n};\n\n/** Grouped pie config — collapses the formerly-separate\n * `pieInnerRadius` / `pieOuterRadius` / `pieCompareInnerRadius` /\n * `pieCompareOuterRadius` / `pieContainerClassName` props into one object. */\nexport type AnalyticsChartPieProps = {\n innerRadius?: number,\n outerRadius?: number,\n compareInnerRadius?: number,\n compareOuterRadius?: number,\n className?: string,\n};\n\nexport type AnalyticsChartSegmentRamp =\n | {\n kind: \"procedural\",\n /** HSL hue (0-360). */\n hue: number,\n /** HSL saturation percent (0-100). */\n sat: number,\n /** Lightness range `[start, end]` for the light theme (0-100). */\n shadeRangeLight: [number, number],\n /** Lightness range `[start, end]` for the dark theme (0-100). */\n shadeRangeDark: [number, number],\n }\n | {\n kind: \"explicit\",\n /** Concrete light-theme color list. Indexed by segment. */\n light: readonly string[],\n /** Concrete dark-theme color list. Indexed by segment. */\n dark: readonly string[],\n };\n\nexport type AnalyticsChartPalette = {\n /** Color ramp for the primary data layer (current period). */\n primary: AnalyticsChartSegmentRamp,\n /** Color ramp for the compare data layer (previous period). */\n compare: AnalyticsChartSegmentRamp,\n};\n"],"mappings":";;AAOA,SAAgB,WAAW,GAAU,IAAoB;CACvD,MAAM,IAAI,EAAE,OAAO;AACnB,QAAO,OAAO,MAAM,YAAY,OAAO,SAAS,EAAE,GAAG,IAAI;;;;;;AAO3D,SAAgB,SAAS,KAAqB;CAG5C,MAAM,UAAU,IAAI,QAAQ,mBAAmB,IAAI;AACnD,QAAO,MAAM,KAAK,QAAQ,GAAG,IAAI,YAAY"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/components/analytics-chart/types.ts"],"sourcesContent":["/** Time-series point. `values` is keyed by layer id. */\nexport type Point = {\n ts: number,\n values: Record<string, number>,\n};\n\n/** Missing or non-finite values become 0. */\nexport function pointValue(p: Point, id: string): number {\n const v = p.values[id];\n return typeof v === \"number\" && Number.isFinite(v) ? v : 0;\n}\n\n/** Sanitize a string into a valid CSS `<ident>` token.\n * Replaces characters not allowed in CSS identifiers (like `$`, spaces,\n * slashes, dots) with underscores. Used to build safe `var(--color-xxx)`\n * custom property names from arbitrary segment keys. */\nexport function cssIdent(raw: string): string {\n // Replace everything that isn't a letter, digit, hyphen, or underscore.\n // Prefix with `_` if the result starts with a digit (not valid as ident start).\n const cleaned = raw.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return /^\\d/.test(cleaned) ? `_${cleaned}` : cleaned;\n}\n\nexport type Annotation = {\n index: number,\n label: string,\n description: string,\n};\n\n/** Breakdown category definition — `{ key, label }` tuple. */\nexport type AnalyticsChartSeries = {\n key: string,\n label: string,\n};\n\nexport type FormatKindType =\n | \"numeric\"\n | \"short\"\n | \"currency\"\n | \"duration\"\n | \"datetime\"\n | \"percent\";\n\nexport type FormatKindNumeric = {\n type: \"numeric\",\n /** Locale used for grouping and digit separators. Defaults to \"en-US\". */\n locale?: string,\n /** Fixed decimal places (0-4). Defaults to 0. */\n decimals?: number,\n};\nexport type FormatKindShort = {\n type: \"short\",\n /** Decimal places after the unit suffix (1.2K vs 1.20K). Defaults to 1. */\n precision?: number,\n locale?: string,\n};\nexport type FormatKindCurrency = {\n type: \"currency\",\n /** ISO 4217 code. Defaults to \"USD\". */\n currency?: string,\n /** Divisor applied before formatting — e.g. 100 for cents → dollars. Defaults to 1. */\n divisor?: number,\n locale?: string,\n};\nexport type FormatKindDuration = {\n type: \"duration\",\n /** Source unit of the input value. Defaults to \"s\". */\n unit?: \"ms\" | \"s\" | \"m\" | \"h\",\n /** Show the smallest unit even when zero. Defaults to false. */\n showZero?: boolean,\n};\nexport type FormatKindDatetime = {\n type: \"datetime\",\n /** Render style. Defaults to \"short\". */\n style?: \"short\" | \"long\" | \"iso\" | \"relative\",\n locale?: string,\n};\nexport type FormatKindPercent = {\n type: \"percent\",\n /** How to interpret the input value:\n * - \"fraction\" → 0..1 → multiply by 100 (default)\n * - \"basis\" → 0..10000 → divide by 100\n * - \"whole\" → 0..100 → no scaling\n */\n source?: \"fraction\" | \"basis\" | \"whole\",\n /** Decimal places. Defaults to 1. */\n decimals?: number,\n};\n\nexport type FormatKind =\n | FormatKindNumeric\n | FormatKindShort\n | FormatKindCurrency\n | FormatKindDuration\n | FormatKindDatetime\n | FormatKindPercent;\n\nexport type AnalyticsChartView = \"timeseries\" | \"pie\";\nexport type AnalyticsChartLayerType = \"line\" | \"area\" | \"bar\";\nexport type AnalyticsChartStrokeStyle = \"solid\" | \"dashed\" | \"dotted\";\n\ntype AnalyticsChartDataLayerCommon = {\n id: string,\n kind: \"primary\" | \"compare\",\n label: string,\n visible: boolean,\n color: string,\n segmented: boolean,\n /** Per-day per-category values. Outer index is the day (matches the\n * chart data array index); inner index is the category (matches\n * `segmentSeries`). Rows should sum to `point.values[layer.id]`. */\n segments?: readonly (readonly number[])[],\n /** Breakdown category definitions ordered to match the inner index of\n * `segments`. */\n segmentSeries?: readonly AnalyticsChartSeries[],\n /** Absolute index into the full data array at which this layer's values\n * become \"in progress\" (incomplete and still changing). Points from this\n * index onward render with a dashed overlay so users don't panic at a\n * half-filled bucket. Applies to line and area rendering only. */\n inProgressFromIndex?: number | null,\n};\nexport type AnalyticsChartLineLayer = AnalyticsChartDataLayerCommon & {\n type: \"line\",\n strokeStyle: AnalyticsChartStrokeStyle,\n};\nexport type AnalyticsChartAreaLayer = AnalyticsChartDataLayerCommon & {\n type: \"area\",\n strokeStyle: AnalyticsChartStrokeStyle,\n fillOpacity: number,\n};\nexport type AnalyticsChartBarLayer = AnalyticsChartDataLayerCommon & {\n type: \"bar\",\n fillOpacity: number,\n};\n\nexport type AnalyticsChartDataLayer =\n | AnalyticsChartLineLayer\n | AnalyticsChartAreaLayer\n | AnalyticsChartBarLayer;\n\nexport type AnalyticsChartAnnotationsLayer = {\n id: string,\n kind: \"annotations\",\n label: string,\n visible: boolean,\n color: string,\n};\n\nexport type AnalyticsChartLayer =\n | AnalyticsChartDataLayer\n | AnalyticsChartAnnotationsLayer;\n\nexport type AnalyticsChartLayers = readonly AnalyticsChartLayer[];\n\nexport type AnalyticsChartTimeseriesState = {\n view: \"timeseries\",\n layers: AnalyticsChartLayers,\n /** Format applied to every x-axis value. Defaults to `datetime / short`. */\n xFormatKind: FormatKind,\n /** Format applied to every y-axis value. Defaults to `short`. */\n yFormatKind: FormatKind,\n showGrid: boolean,\n showXAxis: boolean,\n showYAxis: boolean,\n zoomRange: [number, number] | null,\n pinnedIndex: number | null,\n};\nexport type AnalyticsChartPieState = {\n view: \"pie\",\n layers: AnalyticsChartLayers,\n xFormatKind: FormatKind,\n yFormatKind: FormatKind,\n};\nexport type AnalyticsChartState =\n | AnalyticsChartTimeseriesState\n | AnalyticsChartPieState;\n\nexport type AnalyticsChartDelta = {\n pct: number | null,\n sign: \"up\" | \"down\" | \"flat\" | \"na\",\n};\n\n/** Grouped pie config — collapses the formerly-separate\n * `pieInnerRadius` / `pieOuterRadius` / `pieCompareInnerRadius` /\n * `pieCompareOuterRadius` / `pieContainerClassName` props into one object. */\nexport type AnalyticsChartPieProps = {\n innerRadius?: number,\n outerRadius?: number,\n compareInnerRadius?: number,\n compareOuterRadius?: number,\n className?: string,\n showDateRange?: boolean,\n};\n\nexport type AnalyticsChartSegmentRamp =\n | {\n kind: \"procedural\",\n /** HSL hue (0-360). */\n hue: number,\n /** HSL saturation percent (0-100). */\n sat: number,\n /** Lightness range `[start, end]` for the light theme (0-100). */\n shadeRangeLight: [number, number],\n /** Lightness range `[start, end]` for the dark theme (0-100). */\n shadeRangeDark: [number, number],\n }\n | {\n kind: \"explicit\",\n /** Concrete light-theme color list. Indexed by segment. */\n light: readonly string[],\n /** Concrete dark-theme color list. Indexed by segment. */\n dark: readonly string[],\n };\n\nexport type AnalyticsChartPalette = {\n /** Color ramp for the primary data layer (current period). */\n primary: AnalyticsChartSegmentRamp,\n /** Color ramp for the compare data layer (previous period). */\n compare: AnalyticsChartSegmentRamp,\n};\n"],"mappings":";;AAOA,SAAgB,WAAW,GAAU,IAAoB;CACvD,MAAM,IAAI,EAAE,OAAO;AACnB,QAAO,OAAO,MAAM,YAAY,OAAO,SAAS,EAAE,GAAG,IAAI;;;;;;AAO3D,SAAgB,SAAS,KAAqB;CAG5C,MAAM,UAAU,IAAI,QAAQ,mBAAmB,IAAI;AACnD,QAAO,MAAM,KAAK,QAAQ,GAAG,IAAI,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge.js","names":[],"sources":["../../../src/components/badge.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@
|
|
1
|
+
{"version":3,"file":"badge.js","names":[],"sources":["../../../src/components/badge.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@hexclave/ui\";\n\nexport type DesignBadgeColor = \"blue\" | \"cyan\" | \"purple\" | \"green\" | \"orange\" | \"red\";\nexport type DesignBadgeSize = \"sm\" | \"md\";\n\nconst badgeStyles = new Map<DesignBadgeColor, string>([\n [\"blue\", \"text-blue-700 dark:text-blue-400 bg-blue-500/20 dark:bg-blue-500/10 ring-1 ring-blue-500/30 dark:ring-blue-500/20\"],\n [\"cyan\", \"text-cyan-700 dark:text-cyan-400 bg-cyan-500/20 dark:bg-cyan-500/10 ring-1 ring-cyan-500/30 dark:ring-cyan-500/20\"],\n [\"purple\", \"text-purple-700 dark:text-purple-400 bg-purple-500/20 dark:bg-purple-500/10 ring-1 ring-purple-500/30 dark:ring-purple-500/20\"],\n [\"green\", \"text-emerald-700 dark:text-emerald-400 bg-emerald-500/20 dark:bg-emerald-500/10 ring-1 ring-emerald-500/30 dark:ring-emerald-500/20\"],\n [\"orange\", \"text-amber-700 dark:text-amber-300 bg-amber-500/20 dark:bg-amber-500/10 ring-1 ring-amber-500/30 dark:ring-amber-500/20\"],\n [\"red\", \"text-red-700 dark:text-red-400 bg-red-500/20 dark:bg-red-500/10 ring-1 ring-red-500/30 dark:ring-red-500/20\"],\n]);\n\nfunction getMapValueOrThrow<TKey, TValue>(map: Map<TKey, TValue>, key: TKey, mapName: string) {\n const value = map.get(key);\n if (!value) {\n throw new Error(`Missing ${mapName} entry for key \"${String(key)}\"`);\n }\n return value;\n}\n\n/** At least one of showLabel or showIcon must be true. */\nexport type DesignBadgeContentMode = \"both\" | \"text\" | \"icon\";\n\nexport type DesignBadgeProps = {\n label: string,\n color: DesignBadgeColor,\n icon?: React.ElementType,\n size?: DesignBadgeSize,\n /** What to display: \"both\" (default), \"text\" (label only), or \"icon\" (icon only; requires icon prop). */\n contentMode?: DesignBadgeContentMode,\n};\n\nfunction getShowLabelShowIcon(\n contentMode: DesignBadgeContentMode,\n hasIcon: boolean,\n): { showLabel: boolean, showIcon: boolean } {\n switch (contentMode) {\n case \"both\": {\n return { showLabel: true, showIcon: hasIcon };\n }\n case \"text\": {\n return { showLabel: true, showIcon: false };\n }\n case \"icon\": {\n if (!hasIcon) {\n throw new Error(\"DesignBadge contentMode 'icon' requires the icon prop to be provided.\");\n }\n return { showLabel: false, showIcon: true };\n }\n default: {\n const _exhaustive: never = contentMode;\n throw new Error(`Unknown contentMode: ${String(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Small pill used for status tags, roles, categories, and other short\n * labels. Not a variant-based component — pick a semantic `color` and\n * optionally pass an `icon` (as a component type, not a rendered node).\n *\n * ```tsx\n * <DesignBadge label=\"Verified\" color=\"green\" icon={CheckIcon} />\n * <DesignBadge label=\"Beta\" color=\"purple\" />\n * <DesignBadge label=\"Error\" color=\"red\" size=\"sm\" />\n * ```\n *\n * Notes:\n * - Props are `label` + `color`, NOT `variant` + children.\n * - `color` is one of: `\"blue\" | \"cyan\" | \"purple\" | \"green\" | \"orange\" | \"red\"`.\n * - `icon` is optional but, if set via `contentMode: \"icon\"`, is required.\n */\nexport function DesignBadge({\n label,\n color,\n icon,\n size = \"md\",\n contentMode = \"both\",\n}: DesignBadgeProps) {\n const Icon = icon;\n const { showLabel, showIcon } = getShowLabelShowIcon(contentMode, !!Icon);\n if (!showLabel && !showIcon) {\n throw new Error(\"DesignBadge must show at least label or icon.\");\n }\n const sizeClasses = size === \"sm\"\n ? \"px-2 py-0.5 text-[10px]\"\n : \"px-2.5 py-1 text-[11px]\";\n const colorClasses = getMapValueOrThrow(badgeStyles, color, \"badgeStyles\");\n\n return (\n <div\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full font-medium\",\n colorClasses,\n sizeClasses\n )}\n title={!showLabel ? label : undefined}\n aria-label={label}\n >\n {showIcon && Icon && <Icon className=\"h-3 w-3\" />}\n {showLabel ? label : null}\n </div>\n );\n}\n"],"mappings":";;;;;;AAOA,MAAM,cAAc,IAAI,IAA8B;CACpD,CAAC,QAAQ,oHAAoH;CAC7H,CAAC,QAAQ,oHAAoH;CAC7H,CAAC,UAAU,gIAAgI;CAC3I,CAAC,SAAS,sIAAsI;CAChJ,CAAC,UAAU,0HAA0H;CACrI,CAAC,OAAO,8GAA8G;CACvH,CAAC;AAEF,SAAS,mBAAiC,KAAwB,KAAW,SAAiB;CAC5F,MAAM,QAAQ,IAAI,IAAI,IAAI;AAC1B,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,WAAW,QAAQ,kBAAkB,OAAO,IAAI,CAAC,GAAG;AAEtE,QAAO;;AAeT,SAAS,qBACP,aACA,SAC2C;AAC3C,SAAQ,aAAR;EACE,KAAK,OACH,QAAO;GAAE,WAAW;GAAM,UAAU;GAAS;EAE/C,KAAK,OACH,QAAO;GAAE,WAAW;GAAM,UAAU;GAAO;EAE7C,KAAK;AACH,OAAI,CAAC,QACH,OAAM,IAAI,MAAM,wEAAwE;AAE1F,UAAO;IAAE,WAAW;IAAO,UAAU;IAAM;EAE7C,SAAS;GACP,MAAM,cAAqB;AAC3B,SAAM,IAAI,MAAM,wBAAwB,OAAO,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;AAqBpE,SAAgB,YAAY,EAC1B,OACA,OACA,MACA,OAAO,MACP,cAAc,UACK;CACnB,MAAM,OAAO;CACb,MAAM,EAAE,WAAW,aAAa,qBAAqB,aAAa,CAAC,CAAC,KAAK;AACzE,KAAI,CAAC,aAAa,CAAC,SACjB,OAAM,IAAI,MAAM,gDAAgD;CAElE,MAAM,cAAc,SAAS,OACzB,4BACA;AAGJ,QACE,qBAAC;EACC,WAAW,GACT,6DALe,mBAAmB,aAAa,OAAO,cAAc,EAOpE,YACD;EACD,OAAO,CAAC,YAAY,QAAQ;EAC5B,cAAY;aAEX,YAAY,QAAQ,oBAAC,QAAK,WAAU,YAAY,EAChD,YAAY,QAAQ;GACjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","names":[],"sources":["../../../src/components/button.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport { forwardRefIfNeeded } from \"@
|
|
1
|
+
{"version":3,"file":"button.js","names":[],"sources":["../../../src/components/button.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport { forwardRefIfNeeded } from \"@hexclave/shared/dist/utils/react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport React from \"react\";\n\nimport { cn, Spinner } from \"@hexclave/ui\";\nimport { useAsyncCallback } from \"@hexclave/shared/dist/hooks/use-async-callback\";\nimport { runAsynchronouslyWithAlert } from \"@hexclave/shared/dist/utils/promises\";\n\nconst designButtonVariants = cva(\n \"stack-scope inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline:\n \"border border-input bg-white/85 dark:bg-background hover:bg-white dark:hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n plain: \"\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nexport type DesignOriginalButtonProps = {\n asChild?: boolean,\n} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof designButtonVariants>;\n\nconst DesignOriginalButton = forwardRefIfNeeded<HTMLButtonElement, DesignOriginalButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(designButtonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n }\n);\nDesignOriginalButton.displayName = \"DesignButton\";\n\nexport type DesignButtonProps = {\n onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void | Promise<void>,\n loading?: boolean,\n loadingStyle?: \"spinner\" | \"disabled\",\n} & DesignOriginalButtonProps;\n\n/**\n * Standard button. Variants: `default | destructive | outline | secondary | ghost | link | plain`.\n * Sizes: `default | sm | lg | icon`.\n *\n * ```tsx\n * <DesignButton variant=\"default\" onClick={handleSave}>Save</DesignButton>\n * <DesignButton variant=\"outline\" size=\"sm\" onClick={handleCancel}>Cancel</DesignButton>\n * <DesignButton variant=\"ghost\" size=\"icon\"><PlusIcon className=\"h-4 w-4\" /></DesignButton>\n * ```\n *\n * Pass an async `onClick` and the button will automatically show a spinner\n * while the promise is pending (set `loadingStyle=\"disabled\"` if you prefer\n * a simple disabled state instead).\n */\nexport const DesignButton = forwardRefIfNeeded<HTMLButtonElement, DesignButtonProps>(\n ({ onClick, loading: loadingProp, loadingStyle = \"spinner\", children, size, ...props }, ref) => {\n const [handleClick, isLoading] = useAsyncCallback(async (e: React.MouseEvent<HTMLButtonElement>) => {\n await onClick?.(e);\n }, [onClick]);\n\n const loading = loadingProp || isLoading;\n\n return (\n <DesignOriginalButton\n {...props}\n ref={ref}\n disabled={props.disabled || loading}\n onClick={(e) => runAsynchronouslyWithAlert(handleClick(e))}\n size={size}\n className={cn(\"relative\", loading && \"[&>:not(.stack-button-do-not-hide-when-siblings-are)]:invisible\", props.className)}\n >\n {loadingStyle === \"spinner\" && <Spinner className={cn(\"absolute inset-0 flex items-center justify-center stack-button-do-not-hide-when-siblings-are\", !loading && \"invisible\")} />}\n <Slottable>\n {typeof children === \"string\" ? <span>{children}</span> : children}\n </Slottable>\n </DesignOriginalButton>\n );\n }\n);\nDesignButton.displayName = \"DesignButton\";\n"],"mappings":";;;;;;;;;;AASA,MAAM,uBAAuB,IAC3B,iOACA;CACE,UAAU;EACR,SAAS;GACP,SACE;GACF,aACE;GACF,SACE;GACF,WACE;GACF,OAAO;GACP,MAAM;GACN,OAAO;GACR;EACD,MAAM;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,MAAM;GACP;EACF;CACD,iBAAiB;EACf,SAAS;EACT,MAAM;EACP;CACF,CACF;AAMD,MAAM,uBAAuB,oBAC1B,EAAE,WAAW,SAAS,MAAM,UAAU,OAAO,GAAG,SAAS,QAAQ;AAEhE,QACE,oBAFW,UAAU,OAAO;EAG1B,WAAW,GAAG,qBAAqB;GAAE;GAAS;GAAM;GAAW,CAAC,CAAC;EAC5D;EACL,GAAI;GACJ;EAGP;AACD,qBAAqB,cAAc;;;;;;;;;;;;;;;AAsBnC,MAAa,eAAe,oBACzB,EAAE,SAAS,SAAS,aAAa,eAAe,WAAW,UAAU,MAAM,GAAG,SAAS,QAAQ;CAC9F,MAAM,CAAC,aAAa,aAAa,iBAAiB,OAAO,MAA2C;AAClG,QAAM,UAAU,EAAE;IACjB,CAAC,QAAQ,CAAC;CAEb,MAAM,UAAU,eAAe;AAE/B,QACE,qBAAC;EACC,GAAI;EACC;EACL,UAAU,MAAM,YAAY;EAC5B,UAAU,MAAM,2BAA2B,YAAY,EAAE,CAAC;EACpD;EACN,WAAW,GAAG,YAAY,WAAW,mEAAmE,MAAM,UAAU;aAEvH,iBAAiB,aAAa,oBAAC,WAAQ,WAAW,GAAG,gGAAgG,CAAC,WAAW,YAAY,GAAI,EAClL,oBAAC,uBACE,OAAO,aAAa,WAAW,oBAAC,UAAM,WAAgB,GAAG,WAChD;GACS;EAG5B;AACD,aAAa,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.js","names":[],"sources":["../../../src/components/card.tsx"],"sourcesContent":["\"use client\";\n\nimport { Card } from \"@stackframe/stack-ui\";\nimport { cn } from \"@stackframe/stack-ui\";\nimport React from \"react\";\n\n// ─── Card nesting context ────────────────────────────────────────────────────\n// Components with a `glassmorphic` prop use this to auto-detect whether they\n// sit inside a DesignCard. When they do, glassmorphic defaults to `true`;\n// when they don't, it defaults to `false`.\n\nconst DesignCardNestingContext = React.createContext(false);\n\n/**\n * Returns `true` when the calling component is rendered inside a DesignCard.\n * Useful for deriving a glassmorphic default.\n */\nexport function useInsideDesignCard(): boolean {\n return React.useContext(DesignCardNestingContext);\n}\n\n/**\n * Resolve the effective glassmorphic value.\n * - If the caller passed an explicit boolean → honour it.\n * - Otherwise → fall back to whether we're inside a DesignCard.\n */\nexport function useGlassmorphicDefault(explicit: boolean | undefined): boolean {\n const insideCard = useInsideDesignCard();\n return explicit ?? insideCard;\n}\n\ntype DesignCardGradient = \"blue\" | \"cyan\" | \"purple\" | \"green\" | \"orange\" | \"default\";\n\nconst hoverTintClasses = new Map<DesignCardGradient, string>([\n [\"blue\", \"group-hover:bg-blue-500/[0.03]\"],\n [\"purple\", \"group-hover:bg-purple-500/[0.03]\"],\n [\"green\", \"group-hover:bg-emerald-500/[0.03]\"],\n [\"orange\", \"group-hover:bg-orange-500/[0.03]\"],\n [\"default\", \"group-hover:bg-slate-500/[0.02]\"],\n [\"cyan\", \"group-hover:bg-cyan-500/[0.03]\"],\n]);\n\nconst demoTintClasses = new Map<DesignCardGradient, string>([\n [\"blue\", \"group-hover/tint:bg-blue-500/[0.02]\"],\n [\"purple\", \"group-hover/tint:bg-purple-500/[0.02]\"],\n [\"green\", \"group-hover/tint:bg-emerald-500/[0.02]\"],\n [\"orange\", \"group-hover/tint:bg-orange-500/[0.02]\"],\n [\"default\", \"group-hover/tint:bg-slate-500/[0.015]\"],\n [\"cyan\", \"group-hover/tint:bg-cyan-500/[0.02]\"],\n]);\n\nconst bodyPaddingClass = \"p-5\";\n\n// ─── Discriminated props ──────────────────────────────────────────────────\n// - If title is given, icon is required.\n// - The layout is derived automatically:\n// title + subtitle → \"header\" (full header block with subtitle)\n// title only → \"compact\" (slim bar with border-b)\n// no title → \"bodyOnly\" (just the body)\n\ntype DesignCardBaseProps = {\n glassmorphic?: boolean,\n gradient?: DesignCardGradient,\n contentClassName?: string,\n} & Omit<React.ComponentProps<typeof Card>, \"title\">;\n\ntype WithTitleProps = {\n title: React.ReactNode,\n subtitle?: React.ReactNode,\n icon: React.ElementType,\n actions?: React.ReactNode,\n};\n\ntype WithoutTitleProps = {\n title?: never,\n subtitle?: never,\n icon?: never,\n actions?: never,\n};\n\nexport type DesignCardProps = DesignCardBaseProps & (WithTitleProps | WithoutTitleProps);\n\n/**\n * General-purpose card for grouping related content: section headers,\n * description blocks, chart-less panels, etc. If the content is a\n * big-number metric, use `DesignMetricCard` instead. If it contains a\n * chart, wrap it in `DesignChartCard`.\n *\n * Two shapes, picked automatically by the props you pass:\n *\n * ```tsx\n * // With a header (title requires icon):\n * <DesignCard title=\"Recent activity\" icon={ActivityIcon}>\n * ...body...\n * </DesignCard>\n *\n * // Body-only (no header):\n * <DesignCard>\n * <h2 className=\"text-2xl font-semibold\">Dashboard</h2>\n * <p className=\"text-muted-foreground\">Overview of your user base</p>\n * </DesignCard>\n * ```\n *\n * Rules:\n * - DO NOT add padding classes (`p-6`, `p-5`, etc.) to `className` — the\n * component already has built-in padding and extra padding will look wrong.\n * - If you set `title`, you MUST also set `icon`. The TS types enforce this,\n * but writing `title` without `icon` will fail.\n * - Body-only cards (no `title`) automatically go transparent in dark mode.\n */\nexport function DesignCard({\n title,\n subtitle,\n icon: Icon,\n actions,\n glassmorphic: glassmorphicProp,\n gradient = \"default\",\n children,\n className,\n contentClassName,\n ...props\n}: DesignCardProps) {\n const glassmorphic = glassmorphicProp ?? true;\n const hoverTintClass = hoverTintClasses.get(gradient) ?? \"group-hover:bg-slate-500/[0.02]\";\n const hasContent = React.Children.count(children) > 0;\n\n // Derive layout from which props were provided\n const variant = title != null\n ? (subtitle != null ? \"header\" : \"compact\")\n : \"bodyOnly\";\n\n return (\n <DesignCardNestingContext.Provider value={true}>\n <Card\n className={cn(\n \"group relative rounded-2xl overflow-hidden\",\n glassmorphic && [\n \"bg-white/90 dark:bg-background/60 dark:backdrop-blur-xl border-0 transition-all duration-150 hover:transition-none\",\n \"ring-1 ring-black/[0.06] hover:ring-black/[0.1] dark:ring-white/[0.06] dark:hover:ring-white/[0.1]\",\n \"shadow-none\",\n ],\n glassmorphic && variant === \"bodyOnly\" && \"dark:bg-transparent dark:ring-0 dark:shadow-none\",\n className\n )}\n {...props}\n >\n {glassmorphic && (\n <>\n <div className={cn(\n \"absolute inset-0 bg-gradient-to-br from-foreground/[0.04] dark:from-foreground/[0.02] to-transparent pointer-events-none rounded-2xl\",\n variant === \"bodyOnly\" && \"dark:hidden\"\n )} />\n {variant !== \"bodyOnly\" && (\n <div\n className={cn(\n \"absolute inset-0 transition-colors duration-150 group-hover:transition-none pointer-events-none rounded-2xl\",\n hoverTintClass\n )}\n />\n )}\n </>\n )}\n <div className=\"relative\">\n {variant === \"header\" && (\n <div className={bodyPaddingClass}>\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n {Icon && (\n <div className=\"p-1.5 rounded-lg bg-foreground/[0.06] dark:bg-foreground/[0.04]\">\n <Icon className=\"h-3.5 w-3.5 text-foreground/70 dark:text-muted-foreground\" />\n </div>\n )}\n <span className=\"text-xs font-semibold text-foreground uppercase tracking-wider\">\n {title}\n </span>\n </div>\n {subtitle && (\n <p className=\"text-sm text-muted-foreground mt-1\">\n {subtitle}\n </p>\n )}\n </div>\n {actions && (\n <div className=\"flex-shrink-0\">\n {actions}\n </div>\n )}\n </div>\n </div>\n )}\n {variant === \"compact\" && (\n <div className=\"p-5 flex items-center justify-between gap-4 border-b border-black/[0.12] dark:border-white/[0.06]\">\n <div className=\"flex items-center gap-2 min-w-0\">\n {Icon && (\n <div className=\"p-1.5 rounded-lg bg-foreground/[0.04]\">\n <Icon className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </div>\n )}\n <span className=\"text-xs font-semibold text-foreground uppercase tracking-wider\">\n {title}\n </span>\n </div>\n {actions && (\n <div className=\"flex-shrink-0\">\n {actions}\n </div>\n )}\n </div>\n )}\n {hasContent && (\n <div\n className={cn(\n variant === \"header\" ? \"border-t border-black/[0.12] dark:border-white/[0.06]\" : \"\",\n variant === \"compact\" ? \"px-5 py-4\" : \"\",\n variant === \"bodyOnly\" || variant === \"header\" ? bodyPaddingClass : \"\",\n contentClassName\n )}\n >\n {children}\n </div>\n )}\n </div>\n </Card>\n </DesignCardNestingContext.Provider>\n );\n}\n\nexport type DesignCardTintProps = {\n gradient: DesignCardGradient,\n} & React.ComponentProps<\"div\">\n\nexport function DesignCardTint({\n gradient,\n className,\n children,\n ...props\n}: DesignCardTintProps) {\n const tintClass = demoTintClasses.get(gradient) ?? \"group-hover/tint:bg-slate-500/[0.015]\";\n\n return (\n <div\n className={cn(\n \"group/tint relative rounded-2xl bg-white/90 dark:bg-background/60 dark:backdrop-blur-xl transition-all duration-150 hover:transition-none\",\n \"ring-1 ring-black/[0.06] hover:ring-black/[0.1] dark:ring-white/[0.06] dark:hover:ring-white/[0.1]\",\n \"shadow-none overflow-hidden\",\n className\n )}\n {...props}\n >\n <div className=\"absolute inset-0 bg-gradient-to-br from-foreground/[0.04] dark:from-foreground/[0.02] to-transparent pointer-events-none rounded-2xl\" />\n <div\n className={cn(\n \"absolute inset-0 transition-colors duration-150 group-hover/tint:transition-none pointer-events-none rounded-2xl\",\n tintClass\n )}\n />\n <div className=\"relative\">\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAWA,MAAM,2BAA2B,MAAM,cAAc,MAAM;;;;;AAM3D,SAAgB,sBAA+B;AAC7C,QAAO,MAAM,WAAW,yBAAyB;;;;;;;AAQnD,SAAgB,uBAAuB,UAAwC;CAC7E,MAAM,aAAa,qBAAqB;AACxC,QAAO,YAAY;;AAKrB,MAAM,mBAAmB,IAAI,IAAgC;CAC3D,CAAC,QAAQ,iCAAiC;CAC1C,CAAC,UAAU,mCAAmC;CAC9C,CAAC,SAAS,oCAAoC;CAC9C,CAAC,UAAU,mCAAmC;CAC9C,CAAC,WAAW,kCAAkC;CAC9C,CAAC,QAAQ,iCAAiC;CAC3C,CAAC;AAEF,MAAM,kBAAkB,IAAI,IAAgC;CAC1D,CAAC,QAAQ,sCAAsC;CAC/C,CAAC,UAAU,wCAAwC;CACnD,CAAC,SAAS,yCAAyC;CACnD,CAAC,UAAU,wCAAwC;CACnD,CAAC,WAAW,wCAAwC;CACpD,CAAC,QAAQ,sCAAsC;CAChD,CAAC;AAEF,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DzB,SAAgB,WAAW,EACzB,OACA,UACA,MAAM,MACN,SACA,cAAc,kBACd,WAAW,WACX,UACA,WACA,kBACA,GAAG,SACe;CAClB,MAAM,eAAe,oBAAoB;CACzC,MAAM,iBAAiB,iBAAiB,IAAI,SAAS,IAAI;CACzD,MAAM,aAAa,MAAM,SAAS,MAAM,SAAS,GAAG;CAGpD,MAAM,UAAU,SAAS,OACpB,YAAY,OAAO,WAAW,YAC/B;AAEJ,QACE,oBAAC,yBAAyB;EAAS,OAAO;YACxC,qBAAC;GACC,WAAW,GACT,8CACA,gBAAgB;IACd;IACA;IACA;IACD,EACD,gBAAgB,YAAY,cAAc,oDAC1C,UACD;GACD,GAAI;cAEH,gBACC,4CACE,oBAAC,SAAI,WAAW,GACd,wIACA,YAAY,cAAc,cAC3B,GAAI,EACJ,YAAY,cACX,oBAAC,SACC,WAAW,GACT,+GACA,eACD,GACD,IAEH,EAEL,qBAAC;IAAI,WAAU;;KACZ,YAAY,YACX,oBAAC;MAAI,WAAW;gBACd,qBAAC;OAAI,WAAU;kBACb,qBAAC;QAAI,WAAU;mBACb,qBAAC;SAAI,WAAU;oBACZ,QACC,oBAAC;UAAI,WAAU;oBACb,oBAAC,QAAK,WAAU,8DAA8D;WAC1E,EAER,oBAAC;UAAK,WAAU;oBACb;WACI;UACH,EACL,YACC,oBAAC;SAAE,WAAU;mBACV;UACC;SAEF,EACL,WACC,oBAAC;QAAI,WAAU;kBACZ;SACG;QAEJ;OACF;KAEP,YAAY,aACX,qBAAC;MAAI,WAAU;iBACb,qBAAC;OAAI,WAAU;kBACZ,QACC,oBAAC;QAAI,WAAU;kBACb,oBAAC,QAAK,WAAU,sCAAsC;SAClD,EAER,oBAAC;QAAK,WAAU;kBACb;SACI;QACH,EACL,WACC,oBAAC;OAAI,WAAU;iBACZ;QACG;OAEJ;KAEP,cACC,oBAAC;MACC,WAAW,GACT,YAAY,WAAW,0DAA0D,IACjF,YAAY,YAAY,cAAc,IACtC,YAAY,cAAc,YAAY,WAAW,mBAAmB,IACpE,iBACD;MAEA;OACG;;KAEJ;IACD;GAC2B;;AAQxC,SAAgB,eAAe,EAC7B,UACA,WACA,UACA,GAAG,SACmB;CACtB,MAAM,YAAY,gBAAgB,IAAI,SAAS,IAAI;AAEnD,QACE,qBAAC;EACC,WAAW,GACT,6IACA,sGACA,+BACA,UACD;EACD,GAAI;;GAEJ,oBAAC,SAAI,WAAU,yIAAyI;GACxJ,oBAAC,SACC,WAAW,GACT,oHACA,UACD,GACD;GACF,oBAAC;IAAI,WAAU;IACZ;KACG;;GACF"}
|
|
1
|
+
{"version":3,"file":"card.js","names":[],"sources":["../../../src/components/card.tsx"],"sourcesContent":["\"use client\";\n\nimport { Card } from \"@hexclave/ui\";\nimport { cn } from \"@hexclave/ui\";\nimport React from \"react\";\n\n// ─── Card nesting context ────────────────────────────────────────────────────\n// Components with a `glassmorphic` prop use this to auto-detect whether they\n// sit inside a DesignCard. When they do, glassmorphic defaults to `true`;\n// when they don't, it defaults to `false`.\n\nconst DesignCardNestingContext = React.createContext(false);\n\n/**\n * Returns `true` when the calling component is rendered inside a DesignCard.\n * Useful for deriving a glassmorphic default.\n */\nexport function useInsideDesignCard(): boolean {\n return React.useContext(DesignCardNestingContext);\n}\n\n/**\n * Resolve the effective glassmorphic value.\n * - If the caller passed an explicit boolean → honour it.\n * - Otherwise → fall back to whether we're inside a DesignCard.\n */\nexport function useGlassmorphicDefault(explicit: boolean | undefined): boolean {\n const insideCard = useInsideDesignCard();\n return explicit ?? insideCard;\n}\n\ntype DesignCardGradient = \"blue\" | \"cyan\" | \"purple\" | \"green\" | \"orange\" | \"default\";\n\nconst hoverTintClasses = new Map<DesignCardGradient, string>([\n [\"blue\", \"group-hover:bg-blue-500/[0.03]\"],\n [\"purple\", \"group-hover:bg-purple-500/[0.03]\"],\n [\"green\", \"group-hover:bg-emerald-500/[0.03]\"],\n [\"orange\", \"group-hover:bg-orange-500/[0.03]\"],\n [\"default\", \"group-hover:bg-slate-500/[0.02]\"],\n [\"cyan\", \"group-hover:bg-cyan-500/[0.03]\"],\n]);\n\nconst demoTintClasses = new Map<DesignCardGradient, string>([\n [\"blue\", \"group-hover/tint:bg-blue-500/[0.02]\"],\n [\"purple\", \"group-hover/tint:bg-purple-500/[0.02]\"],\n [\"green\", \"group-hover/tint:bg-emerald-500/[0.02]\"],\n [\"orange\", \"group-hover/tint:bg-orange-500/[0.02]\"],\n [\"default\", \"group-hover/tint:bg-slate-500/[0.015]\"],\n [\"cyan\", \"group-hover/tint:bg-cyan-500/[0.02]\"],\n]);\n\nconst bodyPaddingClass = \"p-5\";\n\n// ─── Discriminated props ──────────────────────────────────────────────────\n// - If title is given, icon is required.\n// - The layout is derived automatically:\n// title + subtitle → \"header\" (full header block with subtitle)\n// title only → \"compact\" (slim bar with border-b)\n// no title → \"bodyOnly\" (just the body)\n\ntype DesignCardBaseProps = {\n glassmorphic?: boolean,\n gradient?: DesignCardGradient,\n contentClassName?: string,\n} & Omit<React.ComponentProps<typeof Card>, \"title\">;\n\ntype WithTitleProps = {\n title: React.ReactNode,\n subtitle?: React.ReactNode,\n icon: React.ElementType,\n actions?: React.ReactNode,\n};\n\ntype WithoutTitleProps = {\n title?: never,\n subtitle?: never,\n icon?: never,\n actions?: never,\n};\n\nexport type DesignCardProps = DesignCardBaseProps & (WithTitleProps | WithoutTitleProps);\n\n/**\n * General-purpose card for grouping related content: section headers,\n * description blocks, chart-less panels, etc. If the content is a\n * big-number metric, use `DesignMetricCard` instead. If it contains a\n * chart, wrap it in `DesignChartCard`.\n *\n * Two shapes, picked automatically by the props you pass:\n *\n * ```tsx\n * // With a header (title requires icon):\n * <DesignCard title=\"Recent activity\" icon={ActivityIcon}>\n * ...body...\n * </DesignCard>\n *\n * // Body-only (no header):\n * <DesignCard>\n * <h2 className=\"text-2xl font-semibold\">Dashboard</h2>\n * <p className=\"text-muted-foreground\">Overview of your user base</p>\n * </DesignCard>\n * ```\n *\n * Rules:\n * - DO NOT add padding classes (`p-6`, `p-5`, etc.) to `className` — the\n * component already has built-in padding and extra padding will look wrong.\n * - If you set `title`, you MUST also set `icon`. The TS types enforce this,\n * but writing `title` without `icon` will fail.\n * - Body-only cards (no `title`) automatically go transparent in dark mode.\n */\nexport function DesignCard({\n title,\n subtitle,\n icon: Icon,\n actions,\n glassmorphic: glassmorphicProp,\n gradient = \"default\",\n children,\n className,\n contentClassName,\n ...props\n}: DesignCardProps) {\n const glassmorphic = glassmorphicProp ?? true;\n const hoverTintClass = hoverTintClasses.get(gradient) ?? \"group-hover:bg-slate-500/[0.02]\";\n const hasContent = React.Children.count(children) > 0;\n\n // Derive layout from which props were provided\n const variant = title != null\n ? (subtitle != null ? \"header\" : \"compact\")\n : \"bodyOnly\";\n\n return (\n <DesignCardNestingContext.Provider value={true}>\n <Card\n className={cn(\n \"group relative rounded-2xl overflow-hidden\",\n glassmorphic && [\n \"bg-white/90 dark:bg-background/60 dark:backdrop-blur-xl border-0 transition-all duration-150 hover:transition-none\",\n \"ring-1 ring-black/[0.06] hover:ring-black/[0.1] dark:ring-white/[0.06] dark:hover:ring-white/[0.1]\",\n \"shadow-none\",\n ],\n glassmorphic && variant === \"bodyOnly\" && \"dark:bg-transparent dark:ring-0 dark:shadow-none\",\n className\n )}\n {...props}\n >\n {glassmorphic && (\n <>\n <div className={cn(\n \"absolute inset-0 bg-gradient-to-br from-foreground/[0.04] dark:from-foreground/[0.02] to-transparent pointer-events-none rounded-2xl\",\n variant === \"bodyOnly\" && \"dark:hidden\"\n )} />\n {variant !== \"bodyOnly\" && (\n <div\n className={cn(\n \"absolute inset-0 transition-colors duration-150 group-hover:transition-none pointer-events-none rounded-2xl\",\n hoverTintClass\n )}\n />\n )}\n </>\n )}\n <div className=\"relative\">\n {variant === \"header\" && (\n <div className={bodyPaddingClass}>\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n {Icon && (\n <div className=\"p-1.5 rounded-lg bg-foreground/[0.06] dark:bg-foreground/[0.04]\">\n <Icon className=\"h-3.5 w-3.5 text-foreground/70 dark:text-muted-foreground\" />\n </div>\n )}\n <span className=\"text-xs font-semibold text-foreground uppercase tracking-wider\">\n {title}\n </span>\n </div>\n {subtitle && (\n <p className=\"text-sm text-muted-foreground mt-1\">\n {subtitle}\n </p>\n )}\n </div>\n {actions && (\n <div className=\"flex-shrink-0\">\n {actions}\n </div>\n )}\n </div>\n </div>\n )}\n {variant === \"compact\" && (\n <div className=\"p-5 flex items-center justify-between gap-4 border-b border-black/[0.12] dark:border-white/[0.06]\">\n <div className=\"flex items-center gap-2 min-w-0\">\n {Icon && (\n <div className=\"p-1.5 rounded-lg bg-foreground/[0.04]\">\n <Icon className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </div>\n )}\n <span className=\"text-xs font-semibold text-foreground uppercase tracking-wider\">\n {title}\n </span>\n </div>\n {actions && (\n <div className=\"flex-shrink-0\">\n {actions}\n </div>\n )}\n </div>\n )}\n {hasContent && (\n <div\n className={cn(\n variant === \"header\" ? \"border-t border-black/[0.12] dark:border-white/[0.06]\" : \"\",\n variant === \"compact\" ? \"px-5 py-4\" : \"\",\n variant === \"bodyOnly\" || variant === \"header\" ? bodyPaddingClass : \"\",\n contentClassName\n )}\n >\n {children}\n </div>\n )}\n </div>\n </Card>\n </DesignCardNestingContext.Provider>\n );\n}\n\nexport type DesignCardTintProps = {\n gradient: DesignCardGradient,\n} & React.ComponentProps<\"div\">\n\nexport function DesignCardTint({\n gradient,\n className,\n children,\n ...props\n}: DesignCardTintProps) {\n const tintClass = demoTintClasses.get(gradient) ?? \"group-hover/tint:bg-slate-500/[0.015]\";\n\n return (\n <div\n className={cn(\n \"group/tint relative rounded-2xl bg-white/90 dark:bg-background/60 dark:backdrop-blur-xl transition-all duration-150 hover:transition-none\",\n \"ring-1 ring-black/[0.06] hover:ring-black/[0.1] dark:ring-white/[0.06] dark:hover:ring-white/[0.1]\",\n \"shadow-none overflow-hidden\",\n className\n )}\n {...props}\n >\n <div className=\"absolute inset-0 bg-gradient-to-br from-foreground/[0.04] dark:from-foreground/[0.02] to-transparent pointer-events-none rounded-2xl\" />\n <div\n className={cn(\n \"absolute inset-0 transition-colors duration-150 group-hover/tint:transition-none pointer-events-none rounded-2xl\",\n tintClass\n )}\n />\n <div className=\"relative\">\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAWA,MAAM,2BAA2B,MAAM,cAAc,MAAM;;;;;AAM3D,SAAgB,sBAA+B;AAC7C,QAAO,MAAM,WAAW,yBAAyB;;;;;;;AAQnD,SAAgB,uBAAuB,UAAwC;CAC7E,MAAM,aAAa,qBAAqB;AACxC,QAAO,YAAY;;AAKrB,MAAM,mBAAmB,IAAI,IAAgC;CAC3D,CAAC,QAAQ,iCAAiC;CAC1C,CAAC,UAAU,mCAAmC;CAC9C,CAAC,SAAS,oCAAoC;CAC9C,CAAC,UAAU,mCAAmC;CAC9C,CAAC,WAAW,kCAAkC;CAC9C,CAAC,QAAQ,iCAAiC;CAC3C,CAAC;AAEF,MAAM,kBAAkB,IAAI,IAAgC;CAC1D,CAAC,QAAQ,sCAAsC;CAC/C,CAAC,UAAU,wCAAwC;CACnD,CAAC,SAAS,yCAAyC;CACnD,CAAC,UAAU,wCAAwC;CACnD,CAAC,WAAW,wCAAwC;CACpD,CAAC,QAAQ,sCAAsC;CAChD,CAAC;AAEF,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DzB,SAAgB,WAAW,EACzB,OACA,UACA,MAAM,MACN,SACA,cAAc,kBACd,WAAW,WACX,UACA,WACA,kBACA,GAAG,SACe;CAClB,MAAM,eAAe,oBAAoB;CACzC,MAAM,iBAAiB,iBAAiB,IAAI,SAAS,IAAI;CACzD,MAAM,aAAa,MAAM,SAAS,MAAM,SAAS,GAAG;CAGpD,MAAM,UAAU,SAAS,OACpB,YAAY,OAAO,WAAW,YAC/B;AAEJ,QACE,oBAAC,yBAAyB;EAAS,OAAO;YACxC,qBAAC;GACC,WAAW,GACT,8CACA,gBAAgB;IACd;IACA;IACA;IACD,EACD,gBAAgB,YAAY,cAAc,oDAC1C,UACD;GACD,GAAI;cAEH,gBACC,4CACE,oBAAC,SAAI,WAAW,GACd,wIACA,YAAY,cAAc,cAC3B,GAAI,EACJ,YAAY,cACX,oBAAC,SACC,WAAW,GACT,+GACA,eACD,GACD,IAEH,EAEL,qBAAC;IAAI,WAAU;;KACZ,YAAY,YACX,oBAAC;MAAI,WAAW;gBACd,qBAAC;OAAI,WAAU;kBACb,qBAAC;QAAI,WAAU;mBACb,qBAAC;SAAI,WAAU;oBACZ,QACC,oBAAC;UAAI,WAAU;oBACb,oBAAC,QAAK,WAAU,8DAA8D;WAC1E,EAER,oBAAC;UAAK,WAAU;oBACb;WACI;UACH,EACL,YACC,oBAAC;SAAE,WAAU;mBACV;UACC;SAEF,EACL,WACC,oBAAC;QAAI,WAAU;kBACZ;SACG;QAEJ;OACF;KAEP,YAAY,aACX,qBAAC;MAAI,WAAU;iBACb,qBAAC;OAAI,WAAU;kBACZ,QACC,oBAAC;QAAI,WAAU;kBACb,oBAAC,QAAK,WAAU,sCAAsC;SAClD,EAER,oBAAC;QAAK,WAAU;kBACb;SACI;QACH,EACL,WACC,oBAAC;OAAI,WAAU;iBACZ;QACG;OAEJ;KAEP,cACC,oBAAC;MACC,WAAW,GACT,YAAY,WAAW,0DAA0D,IACjF,YAAY,YAAY,cAAc,IACtC,YAAY,cAAc,YAAY,WAAW,mBAAmB,IACpE,iBACD;MAEA;OACG;;KAEJ;IACD;GAC2B;;AAQxC,SAAgB,eAAe,EAC7B,UACA,WACA,UACA,GAAG,SACmB;CACtB,MAAM,YAAY,gBAAgB,IAAI,SAAS,IAAI;AAEnD,QACE,qBAAC;EACC,WAAW,GACT,6IACA,sGACA,+BACA,UACD;EACD,GAAI;;GAEJ,oBAAC,SAAI,WAAU,yIAAyI;GACxJ,oBAAC,SACC,WAAW,GACT,oHACA,UACD,GACD;GACF,oBAAC;IAAI,WAAU;IACZ;KACG;;GACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-card.js","names":[],"sources":["../../../src/components/chart-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@
|
|
1
|
+
{"version":3,"file":"chart-card.js","names":[],"sources":["../../../src/components/chart-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@hexclave/ui\";\nimport React from \"react\";\n\ntype DesignChartCardGradient = \"blue\" | \"cyan\" | \"purple\" | \"green\" | \"orange\" | \"default\";\n\nconst hoverTintClasses = new Map<DesignChartCardGradient, string>([\n [\"blue\", \"group-hover:bg-blue-500/[0.03]\"],\n [\"cyan\", \"group-hover:bg-cyan-500/[0.03]\"],\n [\"purple\", \"group-hover:bg-purple-500/[0.03]\"],\n [\"green\", \"group-hover:bg-emerald-500/[0.03]\"],\n [\"orange\", \"group-hover:bg-orange-500/[0.03]\"],\n [\"default\", \"group-hover:bg-slate-500/[0.02]\"],\n]);\n\nexport type DesignChartCardProps = {\n gradient?: DesignChartCardGradient,\n title?: React.ReactNode,\n description?: React.ReactNode,\n} & Omit<React.ComponentProps<\"div\">, \"title\">;\n\n/**\n * Card chrome (title + description + border) for a chart. Wrap every\n * `AnalyticsChart` in this so the chart has context. Also used around raw\n * Recharts components paired with `DesignChartContainer` for non-time-series\n * fallbacks.\n *\n * ```tsx\n * // Time-series chart (preferred):\n * <DesignChartCard title=\"Signups\" description=\"Last 30 days\">\n * <AnalyticsChart data={data} state={state} onChange={setState} />\n * </DesignChartCard>\n *\n * // Non-time-series fallback (static ranking, distribution, etc.):\n * <DesignChartCard title=\"Top referrers\" description=\"This month\">\n * <DesignChartContainer config={chartConfig} maxHeight={300}>\n * <Recharts.BarChart data={data}>\n * <Recharts.CartesianGrid strokeDasharray=\"3 3\" stroke=\"hsl(var(--border))\" />\n * <Recharts.XAxis dataKey=\"name\" tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 12 }} />\n * <Recharts.YAxis tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 12 }} />\n * <Recharts.Tooltip content={<DesignChartTooltipContent />} />\n * <Recharts.Bar dataKey=\"count\" fill={getDesignChartColor(0)} radius={[4, 4, 0, 0]} />\n * </Recharts.BarChart>\n * </DesignChartContainer>\n * </DesignChartCard>\n * ```\n *\n * `chartConfig` for `DesignChartContainer` maps each `dataKey` to its label and color:\n * `{ count: { label: \"Count\", color: getDesignChartColor(0) } }`.\n */\nexport function DesignChartCard({\n gradient = \"default\",\n title,\n description,\n className,\n children,\n ...props\n}: DesignChartCardProps) {\n const hoverTintClass = hoverTintClasses.get(gradient) ?? \"group-hover:bg-slate-500/[0.02]\";\n\n return (\n <>\n <style dangerouslySetInnerHTML={{ __html: `\n .design-chart-card-tooltip-escape .recharts-tooltip-wrapper {\n z-index: 9999 !important;\n overflow: visible !important;\n }\n .design-chart-card-tooltip-escape .recharts-tooltip-wrapper > * {\n overflow: visible !important;\n }\n ` }} />\n <div\n className={cn(\n \"group relative rounded-2xl bg-white/90 dark:bg-background/60 backdrop-blur-xl transition-all duration-150 hover:transition-none design-chart-card-tooltip-escape\",\n \"ring-1 ring-black/[0.06] hover:ring-black/[0.1] dark:ring-white/[0.06] dark:hover:ring-white/[0.1]\",\n \"shadow-sm hover:shadow-md hover:z-10\",\n className\n )}\n {...props}\n >\n <div className=\"absolute inset-0 bg-gradient-to-br from-foreground/[0.04] dark:from-foreground/[0.02] to-transparent pointer-events-none rounded-2xl overflow-hidden\" />\n <div\n className={cn(\n \"absolute inset-0 transition-colors duration-150 group-hover:transition-none pointer-events-none rounded-2xl overflow-hidden\",\n hoverTintClass\n )}\n />\n <div className=\"relative h-full flex flex-col p-4\">\n {(title || description) && (\n <div className=\"mb-3\">\n {title && <h3 className=\"text-sm font-semibold text-foreground\">{title}</h3>}\n {description && <p className=\"text-xs text-muted-foreground mt-0.5\">{description}</p>}\n </div>\n )}\n {children}\n </div>\n </div>\n </>\n );\n}\n"],"mappings":";;;;;;;AAOA,MAAM,mBAAmB,IAAI,IAAqC;CAChE,CAAC,QAAQ,iCAAiC;CAC1C,CAAC,QAAQ,iCAAiC;CAC1C,CAAC,UAAU,mCAAmC;CAC9C,CAAC,SAAS,oCAAoC;CAC9C,CAAC,UAAU,mCAAmC;CAC9C,CAAC,WAAW,kCAAkC;CAC/C,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCF,SAAgB,gBAAgB,EAC9B,WAAW,WACX,OACA,aACA,WACA,UACA,GAAG,SACoB;CACvB,MAAM,iBAAiB,iBAAiB,IAAI,SAAS,IAAI;AAEzD,QACE,4CACE,oBAAC,WAAM,yBAAyB,EAAE,QAAQ;;;;;;;;SAQvC,GAAI,EACP,qBAAC;EACC,WAAW,GACT,oKACA,sGACA,wCACA,UACD;EACD,GAAI;;GAEJ,oBAAC,SAAI,WAAU,yJAAyJ;GACxK,oBAAC,SACC,WAAW,GACT,+HACA,eACD,GACD;GACF,qBAAC;IAAI,WAAU;gBACX,SAAS,gBACT,qBAAC;KAAI,WAAU;gBACZ,SAAS,oBAAC;MAAG,WAAU;gBAAyC;OAAW,EAC3E,eAAe,oBAAC;MAAE,WAAU;gBAAwC;OAAgB;MACjF,EAEP;KACG;;GACF,IACL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-container.js","names":["React"],"sources":["../../../src/components/chart-container.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as RechartsPrimitive from \"recharts\";\nimport { cn } from \"@
|
|
1
|
+
{"version":3,"file":"chart-container.js","names":["React"],"sources":["../../../src/components/chart-container.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as RechartsPrimitive from \"recharts\";\nimport { cn } from \"@hexclave/ui\";\n\nconst THEMES = { light: \"\", dark: \".dark\" } as const;\n\nexport type DesignChartConfig = {\n [k in string]: {\n label?: React.ReactNode,\n icon?: React.ComponentType,\n } & (\n | { color?: string, theme?: never }\n | { color?: never, theme: Record<keyof typeof THEMES, string> }\n )\n};\n\ntype ChartContextProps = {\n config: DesignChartConfig,\n};\n\nconst ChartContext = React.createContext<ChartContextProps | null>(null);\n\nexport function useDesignChart() {\n const context = React.useContext(ChartContext);\n if (!context) {\n throw new Error(\"useDesignChart must be used within a <DesignChartContainer />\");\n }\n return context;\n}\n\nexport function DesignChartStyle({ id, config }: { id: string, config: DesignChartConfig }) {\n const colorConfig = Object.entries(config).filter(\n ([_, cfg]) => cfg.theme || cfg.color\n );\n\n if (!colorConfig.length) {\n return null;\n }\n\n return (\n <style\n dangerouslySetInnerHTML={{\n __html: Object.entries(THEMES)\n .map(\n ([theme, prefix]) => `\n${prefix} [data-chart=${id}] {\n${colorConfig\n .map(([key, itemConfig]) => {\n const color =\n itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||\n itemConfig.color;\n return color ? ` --color-${key}: ${color};` : null;\n })\n .join(\"\\n\")}\n}\n`\n )\n .join(\"\\n\"),\n }}\n />\n );\n}\n\nexport const DesignChartContainer = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> & {\n maxHeight?: number,\n config: DesignChartConfig,\n children: React.ComponentProps<\n typeof RechartsPrimitive.ResponsiveContainer\n >[\"children\"],\n }\n>(({ id, className, children, config, maxHeight, ...props }, ref) => {\n const uniqueId = React.useId();\n const chartId = `chart-${id || uniqueId.replace(/:/g, \"\")}`;\n\n return (\n <ChartContext.Provider value={{ config }}>\n <div\n data-chart={chartId}\n ref={ref}\n className={cn(\n \"flex aspect-video justify-center text-xs\",\n \"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground\",\n \"[&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-black/[0.06] dark:[&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-white/[0.06]\",\n \"[&_.recharts-curve.recharts-tooltip-cursor]:stroke-black/[0.12] dark:[&_.recharts-curve.recharts-tooltip-cursor]:stroke-white/[0.12]\",\n \"[&_.recharts-dot[stroke='#fff']]:stroke-transparent\",\n \"[&_.recharts-layer]:outline-none\",\n \"[&_.recharts-polar-grid_[stroke='#ccc']]:stroke-black/[0.06] dark:[&_.recharts-polar-grid_[stroke='#ccc']]:stroke-white/[0.06]\",\n \"[&_.recharts-radial-bar-background-sector]:fill-black/[0.04] dark:[&_.recharts-radial-bar-background-sector]:fill-white/[0.04]\",\n \"[&_.recharts-rectangle.recharts-tooltip-cursor]:fill-black/[0.04] dark:[&_.recharts-rectangle.recharts-tooltip-cursor]:fill-white/[0.04]\",\n \"[&_.recharts-reference-line_[stroke='#ccc']]:stroke-black/[0.06] dark:[&_.recharts-reference-line_[stroke='#ccc']]:stroke-white/[0.06]\",\n \"[&_.recharts-sector[stroke='#fff']]:stroke-transparent\",\n \"[&_.recharts-sector]:outline-none\",\n \"[&_.recharts-surface]:outline-none\",\n className\n )}\n {...props}\n style={{\n ...props.style,\n maxHeight,\n }}\n >\n <DesignChartStyle id={chartId} config={config} />\n <RechartsPrimitive.ResponsiveContainer maxHeight={maxHeight}>\n {children}\n </RechartsPrimitive.ResponsiveContainer>\n </div>\n </ChartContext.Provider>\n );\n});\nDesignChartContainer.displayName = \"DesignChartContainer\";\n\n/**\n * Helper to extract item config from a Recharts payload object.\n */\nexport function getPayloadConfigFromPayload(\n config: DesignChartConfig,\n payload: unknown,\n key: string,\n) {\n if (typeof payload !== \"object\" || payload === null) {\n return undefined;\n }\n\n const payloadPayload =\n \"payload\" in payload &&\n typeof payload.payload === \"object\" &&\n payload.payload !== null\n ? payload.payload\n : undefined;\n\n let configLabelKey: string = key;\n\n if (\n key in payload &&\n typeof payload[key as keyof typeof payload] === \"string\"\n ) {\n configLabelKey = payload[key as keyof typeof payload] as string;\n } else if (\n payloadPayload &&\n key in payloadPayload &&\n typeof payloadPayload[key as keyof typeof payloadPayload] === \"string\"\n ) {\n configLabelKey = payloadPayload[\n key as keyof typeof payloadPayload\n ] as string;\n }\n\n return configLabelKey in config\n ? config[configLabelKey]\n : config[key as keyof typeof config];\n}\n"],"mappings":";;;;;;;;AAMA,MAAM,SAAS;CAAE,OAAO;CAAI,MAAM;CAAS;AAgB3C,MAAM,eAAeA,QAAM,cAAwC,KAAK;AAExE,SAAgB,iBAAiB;CAC/B,MAAM,UAAUA,QAAM,WAAW,aAAa;AAC9C,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,gEAAgE;AAElF,QAAO;;AAGT,SAAgB,iBAAiB,EAAE,IAAI,UAAqD;CAC1F,MAAM,cAAc,OAAO,QAAQ,OAAO,CAAC,QACxC,CAAC,GAAG,SAAS,IAAI,SAAS,IAAI,MAChC;AAED,KAAI,CAAC,YAAY,OACf,QAAO;AAGT,QACE,oBAAC,WACC,yBAAyB,EACvB,QAAQ,OAAO,QAAQ,OAAO,CAC3B,KACE,CAAC,OAAO,YAAY;EAC/B,OAAO,eAAe,GAAG;EACzB,YACa,KAAK,CAAC,KAAK,gBAAgB;EAC1B,MAAM,QAChB,WAAW,QAAQ,UACnB,WAAW;AACD,SAAO,QAAQ,aAAa,IAAI,IAAI,MAAM,KAAK;GAC/C,CACD,KAAK,KAAK,CAAC;;EAGf,CACA,KAAK,KAAK,EACd,GACD;;AAIN,MAAa,uBAAuBA,QAAM,YASvC,EAAE,IAAI,WAAW,UAAU,QAAQ,WAAW,GAAG,SAAS,QAAQ;CACnE,MAAM,WAAWA,QAAM,OAAO;CAC9B,MAAM,UAAU,SAAS,MAAM,SAAS,QAAQ,MAAM,GAAG;AAEzD,QACE,oBAAC,aAAa;EAAS,OAAO,EAAE,QAAQ;YACtC,qBAAC;GACC,cAAY;GACP;GACL,WAAW,GACT,4CACA,gEACA,kJACA,wIACA,uDACA,oCACA,kIACA,kIACA,4IACA,0IACA,0DACA,qCACA,sCACA,UACD;GACD,GAAI;GACJ,OAAO;IACL,GAAG,MAAM;IACT;IACD;cAED,oBAAC;IAAiB,IAAI;IAAiB;KAAU,EACjD,oBAAC,kBAAkB;IAA+B;IAC/C;KACqC;IACpC;GACgB;EAE1B;AACF,qBAAqB,cAAc;;;;AAKnC,SAAgB,4BACd,QACA,SACA,KACA;AACA,KAAI,OAAO,YAAY,YAAY,YAAY,KAC7C;CAGF,MAAM,iBACJ,aAAa,WACb,OAAO,QAAQ,YAAY,YAC3B,QAAQ,YAAY,OAChB,QAAQ,UACR;CAEN,IAAI,iBAAyB;AAE7B,KACE,OAAO,WACP,OAAO,QAAQ,SAAiC,SAEhD,kBAAiB,QAAQ;UAEzB,kBACA,OAAO,kBACP,OAAO,eAAe,SAAwC,SAE9D,kBAAiB,eACf;AAIJ,QAAO,kBAAkB,SACrB,OAAO,kBACP,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-legend.js","names":["React"],"sources":["../../../src/components/chart-legend.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as RechartsPrimitive from \"recharts\";\nimport { cn } from \"@
|
|
1
|
+
{"version":3,"file":"chart-legend.js","names":["React"],"sources":["../../../src/components/chart-legend.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as RechartsPrimitive from \"recharts\";\nimport { cn } from \"@hexclave/ui\";\nimport { useDesignChart, getPayloadConfigFromPayload } from \"./chart-container\";\n\nexport const DesignChartLegendContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<\"div\"> &\n Pick<RechartsPrimitive.LegendProps, \"payload\" | \"verticalAlign\"> & {\n hideIcon?: boolean,\n nameKey?: string,\n }\n>(\n (\n { className, hideIcon = false, payload, verticalAlign = \"bottom\", nameKey },\n ref\n ) => {\n const { config } = useDesignChart();\n\n if (!payload?.length) {\n return null;\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-wrap items-center justify-center gap-2\",\n verticalAlign === \"top\" ? \"pb-3\" : \"pt-3\",\n className\n )}\n >\n {payload.map((item) => {\n const key = `${nameKey || item.dataKey || \"value\"}`;\n const itemConfig = getPayloadConfigFromPayload(config, item, key);\n\n return (\n <div\n key={item.value}\n className={cn(\n \"flex items-center gap-1.5 rounded-full bg-foreground/[0.03] ring-1 ring-foreground/[0.06] px-3 py-1.5 text-xs\",\n \"transition-colors duration-150 hover:transition-none hover:bg-foreground/[0.05]\"\n )}\n >\n {itemConfig?.icon && !hideIcon ? (\n <itemConfig.icon />\n ) : (\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: item.color }}\n />\n )}\n <span className=\"font-medium text-foreground\">\n {itemConfig?.label || item.value}\n </span>\n </div>\n );\n })}\n </div>\n );\n }\n);\nDesignChartLegendContent.displayName = \"DesignChartLegendContent\";\n"],"mappings":";;;;;;;;AAOA,MAAa,2BAA2BA,QAAM,YAS1C,EAAE,WAAW,WAAW,OAAO,SAAS,gBAAgB,UAAU,WAClE,QACG;CACH,MAAM,EAAE,WAAW,gBAAgB;AAEnC,KAAI,CAAC,SAAS,OACZ,QAAO;AAGT,QACE,oBAAC;EACM;EACL,WAAW,GACT,oDACA,kBAAkB,QAAQ,SAAS,QACnC,UACD;YAEA,QAAQ,KAAK,SAAS;GAErB,MAAM,aAAa,4BAA4B,QAAQ,MAD3C,GAAG,WAAW,KAAK,WAAW,UACuB;AAEjE,UACE,qBAAC;IAEC,WAAW,GACT,iHACA,kFACD;eAEA,YAAY,QAAQ,CAAC,WACpB,oBAAC,WAAW,SAAO,GAEnB,oBAAC;KACC,WAAU;KACV,OAAO,EAAE,iBAAiB,KAAK,OAAO;MACtC,EAEJ,oBAAC;KAAK,WAAU;eACb,YAAY,SAAS,KAAK;MACtB;MAhBF,KAAK,MAiBN;IAER;GACE;EAGX;AACD,yBAAyB,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-tooltip.js","names":["React"],"sources":["../../../src/components/chart-tooltip.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as RechartsPrimitive from \"recharts\";\nimport { cn } from \"@
|
|
1
|
+
{"version":3,"file":"chart-tooltip.js","names":["React"],"sources":["../../../src/components/chart-tooltip.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as RechartsPrimitive from \"recharts\";\nimport { cn } from \"@hexclave/ui\";\nimport { useDesignChart, getPayloadConfigFromPayload } from \"./chart-container\";\n\nexport const DesignChartTooltip = RechartsPrimitive.Tooltip;\n\nexport const DesignChartTooltipContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<typeof RechartsPrimitive.Tooltip> &\n React.ComponentProps<\"div\"> & {\n hideLabel?: boolean,\n hideIndicator?: boolean,\n indicator?: \"line\" | \"dot\" | \"dashed\",\n nameKey?: string,\n labelKey?: string,\n }\n>(\n (\n {\n active,\n payload,\n className,\n indicator = \"dot\",\n hideLabel = false,\n hideIndicator = false,\n label,\n labelFormatter,\n labelClassName,\n formatter,\n color,\n nameKey,\n labelKey,\n },\n ref\n ) => {\n const { config } = useDesignChart();\n\n const tooltipLabel = React.useMemo(() => {\n if (hideLabel || !payload?.length) {\n return null;\n }\n\n const [item] = payload;\n const key = `${labelKey || item.dataKey || item.name || \"value\"}`;\n const itemConfig = getPayloadConfigFromPayload(config, item, key);\n const configEntry = typeof label === \"string\" ? config[label as keyof typeof config] : undefined;\n const value =\n !labelKey && typeof label === \"string\"\n ? configEntry?.label ?? label\n : itemConfig?.label;\n\n if (labelFormatter) {\n return (\n <div className={cn(\"font-medium text-muted-foreground tracking-wide\", labelClassName)}>\n {labelFormatter(value, payload)}\n </div>\n );\n }\n\n if (!value) {\n return null;\n }\n\n return <div className={cn(\"font-medium text-muted-foreground tracking-wide\", labelClassName)}>{value}</div>;\n }, [\n label,\n labelFormatter,\n payload,\n hideLabel,\n labelClassName,\n config,\n labelKey,\n ]);\n\n if (!active || !payload?.length) {\n return null;\n }\n\n const nestLabel = payload.length === 1 && indicator !== \"dot\";\n\n return (\n <div\n ref={ref}\n className={cn(\n \"grid min-w-[8rem] items-start gap-1.5 rounded-xl bg-background/95 px-3.5 py-2.5 text-xs shadow-lg backdrop-blur-xl ring-1 ring-foreground/[0.08]\",\n className\n )}\n style={{ zIndex: 9999 }}\n >\n {!nestLabel ? tooltipLabel : null}\n <div className=\"grid gap-1.5\">\n {payload.map((item, index) => {\n const key = `${nameKey || item.name || item.dataKey || \"value\"}`;\n const itemConfig = getPayloadConfigFromPayload(config, item, key);\n const indicatorColor = color || item.payload.fill || item.color;\n\n return (\n <div\n key={item.dataKey}\n className={cn(\n \"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground\",\n indicator === \"dot\" && \"items-center\"\n )}\n >\n {formatter && item.value !== undefined && item.name ? (\n formatter(item.value, item.name, item, index, item.payload)\n ) : (\n <>\n {itemConfig?.icon ? (\n <itemConfig.icon />\n ) : (\n !hideIndicator && (\n <div\n className={cn(\n \"shrink-0 rounded-full\",\n {\n \"h-2 w-2 ring-2 ring-white/20\": indicator === \"dot\",\n \"w-1 rounded-[2px]\": indicator === \"line\",\n \"w-0 border-[1.5px] border-dashed bg-transparent rounded-[2px]\":\n indicator === \"dashed\",\n \"my-0.5\": nestLabel && indicator === \"dashed\",\n }\n )}\n style={\n {\n \"--color-bg\": indicatorColor,\n \"--color-border\": indicatorColor,\n backgroundColor: indicator === \"dot\" ? indicatorColor : undefined,\n } as React.CSSProperties\n }\n />\n )\n )}\n <div\n className={cn(\n \"flex flex-1 justify-between leading-none\",\n nestLabel ? \"items-end\" : \"items-center\"\n )}\n >\n <div className=\"grid gap-1.5\">\n {nestLabel ? tooltipLabel : null}\n <span className=\"text-[11px] text-muted-foreground\">\n {itemConfig?.label || item.name}\n </span>\n </div>\n {item.value != null && (\n <span className=\"ml-auto font-mono text-xs font-semibold tabular-nums text-foreground\">\n {typeof item.value === \"number\" ? item.value.toLocaleString() : item.value}\n </span>\n )}\n </div>\n </>\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n }\n);\nDesignChartTooltipContent.displayName = \"DesignChartTooltipContent\";\n"],"mappings":";;;;;;;;;AAOA,MAAa,qBAAqB,kBAAkB;AAEpD,MAAa,4BAA4BA,QAAM,YAY3C,EACE,QACA,SACA,WACA,YAAY,OACZ,YAAY,OACZ,gBAAgB,OAChB,OACA,gBACA,gBACA,WACA,OACA,SACA,YAEF,QACG;CACH,MAAM,EAAE,WAAW,gBAAgB;CAEnC,MAAM,eAAeA,QAAM,cAAc;AACvC,MAAI,aAAa,CAAC,SAAS,OACzB,QAAO;EAGT,MAAM,CAAC,QAAQ;EAEf,MAAM,aAAa,4BAA4B,QAAQ,MAD3C,GAAG,YAAY,KAAK,WAAW,KAAK,QAAQ,UACS;EACjE,MAAM,cAAc,OAAO,UAAU,WAAW,OAAO,SAAgC;EACvF,MAAM,QACJ,CAAC,YAAY,OAAO,UAAU,WAC1B,aAAa,SAAS,QACtB,YAAY;AAElB,MAAI,eACF,QACE,oBAAC;GAAI,WAAW,GAAG,mDAAmD,eAAe;aAClF,eAAe,OAAO,QAAQ;IAC3B;AAIV,MAAI,CAAC,MACH,QAAO;AAGT,SAAO,oBAAC;GAAI,WAAW,GAAG,mDAAmD,eAAe;aAAG;IAAY;IAC1G;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,KAAI,CAAC,UAAU,CAAC,SAAS,OACvB,QAAO;CAGT,MAAM,YAAY,QAAQ,WAAW,KAAK,cAAc;AAExD,QACE,qBAAC;EACM;EACL,WAAW,GACT,oJACA,UACD;EACD,OAAO,EAAE,QAAQ,MAAM;aAEtB,CAAC,YAAY,eAAe,MAC7B,oBAAC;GAAI,WAAU;aACZ,QAAQ,KAAK,MAAM,UAAU;IAE5B,MAAM,aAAa,4BAA4B,QAAQ,MAD3C,GAAG,WAAW,KAAK,QAAQ,KAAK,WAAW,UACU;IACjE,MAAM,iBAAiB,SAAS,KAAK,QAAQ,QAAQ,KAAK;AAE1D,WACE,oBAAC;KAEC,WAAW,GACT,uGACA,cAAc,SAAS,eACxB;eAEA,aAAa,KAAK,UAAU,UAAa,KAAK,OAC7C,UAAU,KAAK,OAAO,KAAK,MAAM,MAAM,OAAO,KAAK,QAAQ,GAE3D,4CACG,YAAY,OACX,oBAAC,WAAW,SAAO,GAEnB,CAAC,iBACC,oBAAC;MACC,WAAW,GACT,yBACA;OACE,gCAAgC,cAAc;OAC9C,qBAAqB,cAAc;OACnC,iEACE,cAAc;OAChB,UAAU,aAAa,cAAc;OACtC,CACF;MACD,OACE;OACE,cAAc;OACd,kBAAkB;OAClB,iBAAiB,cAAc,QAAQ,iBAAiB;OACzD;OAEH,EAGN,qBAAC;MACC,WAAW,GACT,4CACA,YAAY,cAAc,eAC3B;iBAED,qBAAC;OAAI,WAAU;kBACZ,YAAY,eAAe,MAC5B,oBAAC;QAAK,WAAU;kBACb,YAAY,SAAS,KAAK;SACtB;QACH,EACL,KAAK,SAAS,QACb,oBAAC;OAAK,WAAU;iBACb,OAAO,KAAK,UAAU,WAAW,KAAK,MAAM,gBAAgB,GAAG,KAAK;QAChE;OAEL,IACL;OArDA,KAAK,QAuDN;KAER;IACE;GACF;EAGX;AACD,0BAA0B,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid-toolbar.js","names":[],"sources":["../../../../src/components/data-grid/data-grid-toolbar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@stackframe/stack-ui\";\nimport {\n Check,\n DownloadSimple,\n Eye,\n EyeSlash,\n MagnifyingGlass,\n X,\n} from \"@phosphor-icons/react\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridStrings,\n DataGridToolbarContext,\n} from \"./types\";\n\n// ─── Popover primitive ───────────────────────────────────────────────\n\nfunction usePopover() {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [open]);\n\n return { open, setOpen, ref };\n}\n\nfunction PopoverPanel({\n children,\n className,\n popoverRef,\n}: {\n children: React.ReactNode;\n className?: string;\n popoverRef: React.Ref<HTMLDivElement>;\n}) {\n return (\n <div\n ref={popoverRef}\n className={cn(\n \"absolute top-full left-0 mt-1 z-50\",\n \"bg-popover text-popover-foreground rounded-xl shadow-lg\",\n \"ring-1 ring-black/[0.08] dark:ring-white/[0.1]\",\n \"backdrop-blur-xl\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n// ─── Quick search ────────────────────────────────────────────────────\n\nfunction QuickSearch({\n value,\n onChange,\n placeholder,\n}: {\n value: string;\n onChange: (value: string) => void;\n placeholder: string;\n}) {\n return (\n <div className=\"relative flex min-w-0 flex-1 items-center sm:flex-initial\">\n <MagnifyingGlass className=\"absolute left-2.5 h-3.5 w-3.5 text-muted-foreground/50 pointer-events-none\" />\n <input\n type=\"text\"\n className={cn(\n \"h-8 w-full sm:w-52 pl-8 pr-7 rounded-xl text-xs\",\n \"bg-background\",\n \"border border-black/[0.08] dark:border-white/[0.08]\",\n \"placeholder:text-muted-foreground/40\",\n \"focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"transition-all duration-150\",\n )}\n placeholder={placeholder}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n />\n {value && (\n <button\n className=\"absolute right-2 text-muted-foreground/40 hover:text-muted-foreground\"\n onClick={() => onChange(\"\")}\n aria-label=\"Clear search\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n );\n}\n\n// ─── Toolbar button ──────────────────────────────────────────────────\n\nfunction ToolbarButton({\n children,\n onClick,\n active,\n title,\n className: extraClassName,\n}: {\n children: React.ReactNode;\n onClick?: () => void;\n active?: boolean;\n title?: string;\n className?: string;\n}) {\n return (\n <button\n className={cn(\n \"relative flex items-center justify-center rounded-lg text-xs font-medium\",\n \"h-7 w-7\",\n \"transition-colors duration-75\",\n active\n ? \"bg-foreground/[0.06] text-foreground\"\n : \"text-muted-foreground hover:text-foreground hover:bg-foreground/[0.04]\",\n extraClassName,\n )}\n onClick={onClick}\n title={title}\n >\n {children}\n </button>\n );\n}\n\n// ─── Column manager ──────────────────────────────────────────────────\n\nfunction ColumnManager<TRow>({\n columns,\n visibility,\n onChange,\n strings,\n dateDisplay,\n onDateDisplayChange,\n hasDateColumns,\n}: {\n columns: readonly DataGridColumnDef<TRow>[];\n visibility: Record<string, boolean>;\n onChange: (visibility: Record<string, boolean>) => void;\n strings: DataGridStrings;\n dateDisplay: DataGridDateDisplay;\n onDateDisplayChange: (mode: DataGridDateDisplay) => void;\n hasDateColumns: boolean;\n}) {\n const hideableColumns = useMemo(\n () => columns.filter((c) => c.hideable !== false),\n [columns],\n );\n\n const toggleColumn = (id: string) => {\n const current = visibility[id] !== false;\n onChange({ ...visibility, [id]: !current });\n };\n\n const showAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = true;\n onChange(next);\n };\n\n const hideAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = false;\n onChange(next);\n };\n\n return (\n <div className=\"p-2 min-w-[240px] max-w-[300px]\">\n <div className=\"max-h-[280px] overflow-y-auto space-y-0.5\">\n {hideableColumns.map((col) => {\n const visible = visibility[col.id] !== false;\n return (\n <button\n key={col.id}\n className={cn(\n \"flex items-center gap-2 w-full px-2.5 py-1.5 rounded-lg text-xs\",\n \"hover:bg-foreground/[0.06] transition-colors duration-75\",\n visible ? \"text-foreground\" : \"text-muted-foreground/50\",\n )}\n onClick={() => toggleColumn(col.id)}\n >\n {visible ? (\n <Eye className=\"h-3.5 w-3.5 flex-shrink-0 text-blue-500\" />\n ) : (\n <EyeSlash className=\"h-3.5 w-3.5 flex-shrink-0\" />\n )}\n <span className=\"truncate text-left\">\n {typeof col.header === \"string\" ? col.header : col.id}\n </span>\n {visible && <Check className=\"h-3 w-3 ml-auto flex-shrink-0 text-blue-500\" />}\n </button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 mt-2 pt-2 border-t border-foreground/[0.06]\">\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={showAll}>\n {strings.showAll}\n </button>\n <span className=\"text-muted-foreground/20\">|</span>\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={hideAll}>\n {strings.hideAll}\n </button>\n </div>\n\n {/* Date format toggle — only rendered when at least one column\n uses `type: \"date\"` or `\"dateTime\"`. Toggling writes to\n `state.dateDisplay` and the grid re-renders every date cell. */}\n {hasDateColumns && (\n <div className=\"mt-2 pt-2 border-t border-foreground/[0.06]\">\n <div className=\"flex items-center justify-between gap-2 px-1\">\n <span className=\"text-[10px] font-medium uppercase tracking-wider text-muted-foreground\">\n {strings.dateFormat}\n </span>\n <div className=\"inline-flex items-center gap-0.5 rounded-lg bg-foreground/[0.04] p-0.5\">\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-75\",\n dateDisplay === \"relative\"\n ? \"bg-background text-foreground shadow-sm ring-1 ring-foreground/[0.06]\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n onClick={() => onDateDisplayChange(\"relative\")}\n >\n {strings.dateFormatRelative}\n </button>\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-75\",\n dateDisplay === \"absolute\"\n ? \"bg-background text-foreground shadow-sm ring-1 ring-foreground/[0.06]\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n onClick={() => onDateDisplayChange(\"absolute\")}\n >\n {strings.dateFormatAbsolute}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ─── Main toolbar ────────────────────────────────────────────────────\n\nexport function DataGridToolbar<TRow>({\n ctx,\n extra,\n extraLeading,\n hideQuickSearch,\n}: {\n ctx: DataGridToolbarContext<TRow>;\n /** Extra content rendered inside the toolbar row, to the left of the\n * built-in columns / export actions. Use this to add table-specific\n * affordances (refresh, custom toggles, row counts) without giving up\n * the default actions. */\n extra?: React.ReactNode;\n /** Extra content rendered at the START of the toolbar row — occupies\n * the same position as the built-in quick search (after it, if the\n * quick search is visible). Use this together with `hideQuickSearch`\n * to fully replace the quick search with a custom input, e.g. an\n * AI-powered search bar. */\n extraLeading?: React.ReactNode;\n /** Whether to hide the built-in quick-search input. When `true`,\n * callers are expected to provide their own search UI via\n * `extraLeading`. */\n hideQuickSearch?: boolean;\n}) {\n const { state, onChange, columns, strings, exportCsv } = ctx;\n\n const columnPopover = usePopover();\n\n const updateVisibility = useCallback(\n (visibility: Record<string, boolean>) => {\n onChange((s) => ({ ...s, columnVisibility: visibility }));\n },\n [onChange],\n );\n\n const updateDateDisplay = useCallback(\n (mode: DataGridDateDisplay) => {\n onChange((s) => ({ ...s, dateDisplay: mode }));\n },\n [onChange],\n );\n\n const updateQuickSearch = useCallback(\n (value: string) => {\n onChange((s) => ({\n ...s,\n quickSearch: value,\n // Reset to first page whenever the search text changes,\n // otherwise you can end up on a page index that no longer\n // exists in the filtered / refetched result set.\n pagination: { ...s.pagination, pageIndex: 0 },\n }));\n },\n [onChange],\n );\n\n const hasDateColumns = useMemo(\n () => columns.some((c) => c.type === \"date\" || c.type === \"dateTime\"),\n [columns],\n );\n\n return (\n <div className=\"flex w-full min-w-0 flex-col gap-2 px-2.5 py-2.5 border-b border-foreground/[0.06] sm:flex-row sm:items-center sm:gap-2\">\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\">\n {!hideQuickSearch && (\n <QuickSearch\n value={state.quickSearch}\n onChange={updateQuickSearch}\n placeholder={strings.searchPlaceholder}\n />\n )}\n {extraLeading}\n {extra}\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-2\">\n <div className=\"relative shrink-0\" ref={columnPopover.ref}>\n <ToolbarButton\n onClick={() => columnPopover.setOpen(!columnPopover.open)}\n active={columnPopover.open}\n title={strings.columns}\n >\n <Eye className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n {columnPopover.open && (\n <PopoverPanel popoverRef={columnPopover.ref} className=\"right-0 left-auto\">\n <ColumnManager\n columns={columns}\n visibility={state.columnVisibility}\n onChange={updateVisibility}\n strings={strings}\n dateDisplay={state.dateDisplay}\n onDateDisplayChange={updateDateDisplay}\n hasDateColumns={hasDateColumns}\n />\n </PopoverPanel>\n )}\n </div>\n\n <ToolbarButton onClick={exportCsv} title={strings.export}>\n <DownloadSimple className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAqBA,SAAS,aAAa;CACpB,MAAM,CAAC,MAAM,WAAW,SAAS,MAAM;CACvC,MAAM,MAAM,OAAuB,KAAK;AAExC,OAAM,gBAAgB;AACpB,MAAI,CAAC,KAAM;EACX,MAAM,WAAW,MAAkB;AACjC,OAAI,IAAI,WAAW,CAAC,IAAI,QAAQ,SAAS,EAAE,OAAe,CACxD,SAAQ,MAAM;;AAGlB,WAAS,iBAAiB,aAAa,QAAQ;AAC/C,eAAa,SAAS,oBAAoB,aAAa,QAAQ;IAC9D,CAAC,KAAK,CAAC;AAEV,OAAM,gBAAgB;AACpB,MAAI,CAAC,KAAM;EACX,MAAM,WAAW,MAAqB;AACpC,OAAI,EAAE,QAAQ,SAAU,SAAQ,MAAM;;AAExC,WAAS,iBAAiB,WAAW,QAAQ;AAC7C,eAAa,SAAS,oBAAoB,WAAW,QAAQ;IAC5D,CAAC,KAAK,CAAC;AAEV,QAAO;EAAE;EAAM;EAAS;EAAK;;AAG/B,SAAS,aAAa,EACpB,UACA,WACA,cAKC;AACD,QACE,oBAAC;EACC,KAAK;EACL,WAAW,GACT,sCACA,2DACA,kDACA,oBACA,UACD;EAEA;GACG;;AAMV,SAAS,YAAY,EACnB,OACA,UACA,eAKC;AACD,QACE,qBAAC;EAAI,WAAU;;GACb,oBAAC,mBAAgB,WAAU,+EAA+E;GAC1G,oBAAC;IACC,MAAK;IACL,WAAW,GACT,mDACA,iBACA,uDACA,wCACA,+DACA,8BACD;IACY;IACN;IACP,WAAW,MAAM,SAAS,EAAE,OAAO,MAAM;KACzC;GACD,SACC,oBAAC;IACC,WAAU;IACV,eAAe,SAAS,GAAG;IAC3B,cAAW;cAEX,oBAAC,KAAE,WAAU,YAAY;KAClB;;GAEP;;AAMV,SAAS,cAAc,EACrB,UACA,SACA,QACA,OACA,WAAW,kBAOV;AACD,QACE,oBAAC;EACC,WAAW,GACT,4EACA,WACA,iCACA,SACI,yCACA,0EACJ,eACD;EACQ;EACF;EAEN;GACM;;AAMb,SAAS,cAAoB,EAC3B,SACA,YACA,UACA,SACA,aACA,qBACA,kBASC;CACD,MAAM,kBAAkB,cAChB,QAAQ,QAAQ,MAAM,EAAE,aAAa,MAAM,EACjD,CAAC,QAAQ,CACV;CAED,MAAM,gBAAgB,OAAe;EACnC,MAAM,UAAU,WAAW,QAAQ;AACnC,WAAS;GAAE,GAAG;IAAa,KAAK,CAAC;GAAS,CAAC;;CAG7C,MAAM,gBAAgB;EACpB,MAAM,OAAO,EAAE,GAAG,YAAY;AAC9B,OAAK,MAAM,OAAO,gBAAiB,MAAK,IAAI,MAAM;AAClD,WAAS,KAAK;;CAGhB,MAAM,gBAAgB;EACpB,MAAM,OAAO,EAAE,GAAG,YAAY;AAC9B,OAAK,MAAM,OAAO,gBAAiB,MAAK,IAAI,MAAM;AAClD,WAAS,KAAK;;AAGhB,QACE,qBAAC;EAAI,WAAU;;GACb,oBAAC;IAAI,WAAU;cACZ,gBAAgB,KAAK,QAAQ;KAC5B,MAAM,UAAU,WAAW,IAAI,QAAQ;AACvC,YACE,qBAAC;MAEC,WAAW,GACT,mEACA,4DACA,UAAU,oBAAoB,2BAC/B;MACD,eAAe,aAAa,IAAI,GAAG;;OAElC,UACC,oBAAC,OAAI,WAAU,4CAA4C,GAE3D,oBAAC,YAAS,WAAU,8BAA8B;OAEpD,oBAAC;QAAK,WAAU;kBACb,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS,IAAI;SAC9C;OACN,WAAW,oBAAC,SAAM,WAAU,gDAAgD;;QAhBxE,IAAI,GAiBF;MAEX;KACE;GACN,qBAAC;IAAI,WAAU;;KACb,oBAAC;MAAO,WAAU;MAA6H,SAAS;gBACrJ,QAAQ;OACF;KACT,oBAAC;MAAK,WAAU;gBAA2B;OAAQ;KACnD,oBAAC;MAAO,WAAU;MAA6H,SAAS;gBACrJ,QAAQ;OACF;;KACL;GAKL,kBACC,oBAAC;IAAI,WAAU;cACb,qBAAC;KAAI,WAAU;gBACb,oBAAC;MAAK,WAAU;gBACb,QAAQ;OACJ,EACP,qBAAC;MAAI,WAAU;iBACb,oBAAC;OACC,WAAW,GACT,gFACA,gBAAgB,aACZ,0EACA,8CACL;OACD,eAAe,oBAAoB,WAAW;iBAE7C,QAAQ;QACF,EACT,oBAAC;OACC,WAAW,GACT,gFACA,gBAAgB,aACZ,0EACA,8CACL;OACD,eAAe,oBAAoB,WAAW;iBAE7C,QAAQ;QACF;OACL;MACF;KACF;;GAEJ;;AAMV,SAAgB,gBAAsB,EACpC,KACA,OACA,cACA,mBAkBC;CACD,MAAM,EAAE,OAAO,UAAU,SAAS,SAAS,cAAc;CAEzD,MAAM,gBAAgB,YAAY;CAElC,MAAM,mBAAmB,aACtB,eAAwC;AACvC,YAAU,OAAO;GAAE,GAAG;GAAG,kBAAkB;GAAY,EAAE;IAE3D,CAAC,SAAS,CACX;CAED,MAAM,oBAAoB,aACvB,SAA8B;AAC7B,YAAU,OAAO;GAAE,GAAG;GAAG,aAAa;GAAM,EAAE;IAEhD,CAAC,SAAS,CACX;CAED,MAAM,oBAAoB,aACvB,UAAkB;AACjB,YAAU,OAAO;GACf,GAAG;GACH,aAAa;GAIb,YAAY;IAAE,GAAG,EAAE;IAAY,WAAW;IAAG;GAC9C,EAAE;IAEL,CAAC,SAAS,CACX;CAED,MAAM,iBAAiB,cACf,QAAQ,MAAM,MAAM,EAAE,SAAS,UAAU,EAAE,SAAS,WAAW,EACrE,CAAC,QAAQ,CACV;AAED,QACE,qBAAC;EAAI,WAAU;aACb,qBAAC;GAAI,WAAU;;IACZ,CAAC,mBACA,oBAAC;KACC,OAAO,MAAM;KACb,UAAU;KACV,aAAa,QAAQ;MACrB;IAEH;IACA;;IACG,EACN,qBAAC;GAAI,WAAU;cACb,qBAAC;IAAI,WAAU;IAAoB,KAAK,cAAc;eACpD,oBAAC;KACC,eAAe,cAAc,QAAQ,CAAC,cAAc,KAAK;KACzD,QAAQ,cAAc;KACtB,OAAO,QAAQ;eAEf,oBAAC,OAAI,WAAU,gBAAgB;MACjB,EACf,cAAc,QACb,oBAAC;KAAa,YAAY,cAAc;KAAK,WAAU;eACrD,oBAAC;MACU;MACT,YAAY,MAAM;MAClB,UAAU;MACD;MACT,aAAa,MAAM;MACnB,qBAAqB;MACL;OAChB;MACW;KAEb,EAEN,oBAAC;IAAc,SAAS;IAAW,OAAO,QAAQ;cAChD,oBAAC,kBAAe,WAAU,gBAAgB;KAC5B;IACZ;GACF"}
|
|
1
|
+
{"version":3,"file":"data-grid-toolbar.js","names":[],"sources":["../../../../src/components/data-grid/data-grid-toolbar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@hexclave/ui\";\nimport {\n Check,\n DownloadSimple,\n Eye,\n EyeSlash,\n MagnifyingGlass,\n X,\n} from \"@phosphor-icons/react\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridStrings,\n DataGridToolbarContext,\n} from \"./types\";\n\n// ─── Popover primitive ───────────────────────────────────────────────\n\nfunction usePopover() {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [open]);\n\n return { open, setOpen, ref };\n}\n\nfunction PopoverPanel({\n children,\n className,\n popoverRef,\n}: {\n children: React.ReactNode;\n className?: string;\n popoverRef: React.Ref<HTMLDivElement>;\n}) {\n return (\n <div\n ref={popoverRef}\n className={cn(\n \"absolute top-full left-0 mt-1 z-50\",\n \"bg-popover text-popover-foreground rounded-xl shadow-lg\",\n \"ring-1 ring-black/[0.08] dark:ring-white/[0.1]\",\n \"backdrop-blur-xl\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n// ─── Quick search ────────────────────────────────────────────────────\n\nfunction QuickSearch({\n value,\n onChange,\n placeholder,\n}: {\n value: string;\n onChange: (value: string) => void;\n placeholder: string;\n}) {\n return (\n <div className=\"relative flex min-w-0 flex-1 items-center sm:flex-initial\">\n <MagnifyingGlass className=\"absolute left-2.5 h-3.5 w-3.5 text-muted-foreground/50 pointer-events-none\" />\n <input\n type=\"text\"\n className={cn(\n \"h-8 w-full sm:w-52 pl-8 pr-7 rounded-xl text-xs\",\n \"bg-background\",\n \"border border-black/[0.08] dark:border-white/[0.08]\",\n \"placeholder:text-muted-foreground/40\",\n \"focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"transition-all duration-150\",\n )}\n placeholder={placeholder}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n />\n {value && (\n <button\n className=\"absolute right-2 text-muted-foreground/40 hover:text-muted-foreground\"\n onClick={() => onChange(\"\")}\n aria-label=\"Clear search\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n );\n}\n\n// ─── Toolbar button ──────────────────────────────────────────────────\n\nfunction ToolbarButton({\n children,\n onClick,\n active,\n title,\n className: extraClassName,\n}: {\n children: React.ReactNode;\n onClick?: () => void;\n active?: boolean;\n title?: string;\n className?: string;\n}) {\n return (\n <button\n className={cn(\n \"relative flex items-center justify-center rounded-lg text-xs font-medium\",\n \"h-7 w-7\",\n \"transition-colors duration-75\",\n active\n ? \"bg-foreground/[0.06] text-foreground\"\n : \"text-muted-foreground hover:text-foreground hover:bg-foreground/[0.04]\",\n extraClassName,\n )}\n onClick={onClick}\n title={title}\n >\n {children}\n </button>\n );\n}\n\n// ─── Column manager ──────────────────────────────────────────────────\n\nfunction ColumnManager<TRow>({\n columns,\n visibility,\n onChange,\n strings,\n dateDisplay,\n onDateDisplayChange,\n hasDateColumns,\n}: {\n columns: readonly DataGridColumnDef<TRow>[];\n visibility: Record<string, boolean>;\n onChange: (visibility: Record<string, boolean>) => void;\n strings: DataGridStrings;\n dateDisplay: DataGridDateDisplay;\n onDateDisplayChange: (mode: DataGridDateDisplay) => void;\n hasDateColumns: boolean;\n}) {\n const hideableColumns = useMemo(\n () => columns.filter((c) => c.hideable !== false),\n [columns],\n );\n\n const toggleColumn = (id: string) => {\n const current = visibility[id] !== false;\n onChange({ ...visibility, [id]: !current });\n };\n\n const showAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = true;\n onChange(next);\n };\n\n const hideAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = false;\n onChange(next);\n };\n\n return (\n <div className=\"p-2 min-w-[240px] max-w-[300px]\">\n <div className=\"max-h-[280px] overflow-y-auto space-y-0.5\">\n {hideableColumns.map((col) => {\n const visible = visibility[col.id] !== false;\n return (\n <button\n key={col.id}\n className={cn(\n \"flex items-center gap-2 w-full px-2.5 py-1.5 rounded-lg text-xs\",\n \"hover:bg-foreground/[0.06] transition-colors duration-75\",\n visible ? \"text-foreground\" : \"text-muted-foreground/50\",\n )}\n onClick={() => toggleColumn(col.id)}\n >\n {visible ? (\n <Eye className=\"h-3.5 w-3.5 flex-shrink-0 text-blue-500\" />\n ) : (\n <EyeSlash className=\"h-3.5 w-3.5 flex-shrink-0\" />\n )}\n <span className=\"truncate text-left\">\n {typeof col.header === \"string\" ? col.header : col.id}\n </span>\n {visible && <Check className=\"h-3 w-3 ml-auto flex-shrink-0 text-blue-500\" />}\n </button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 mt-2 pt-2 border-t border-foreground/[0.06]\">\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={showAll}>\n {strings.showAll}\n </button>\n <span className=\"text-muted-foreground/20\">|</span>\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={hideAll}>\n {strings.hideAll}\n </button>\n </div>\n\n {/* Date format toggle — only rendered when at least one column\n uses `type: \"date\"` or `\"dateTime\"`. Toggling writes to\n `state.dateDisplay` and the grid re-renders every date cell. */}\n {hasDateColumns && (\n <div className=\"mt-2 pt-2 border-t border-foreground/[0.06]\">\n <div className=\"flex items-center justify-between gap-2 px-1\">\n <span className=\"text-[10px] font-medium uppercase tracking-wider text-muted-foreground\">\n {strings.dateFormat}\n </span>\n <div className=\"inline-flex items-center gap-0.5 rounded-lg bg-foreground/[0.04] p-0.5\">\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-75\",\n dateDisplay === \"relative\"\n ? \"bg-background text-foreground shadow-sm ring-1 ring-foreground/[0.06]\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n onClick={() => onDateDisplayChange(\"relative\")}\n >\n {strings.dateFormatRelative}\n </button>\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-75\",\n dateDisplay === \"absolute\"\n ? \"bg-background text-foreground shadow-sm ring-1 ring-foreground/[0.06]\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n onClick={() => onDateDisplayChange(\"absolute\")}\n >\n {strings.dateFormatAbsolute}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ─── Main toolbar ────────────────────────────────────────────────────\n\nexport function DataGridToolbar<TRow>({\n ctx,\n extra,\n extraLeading,\n hideQuickSearch,\n}: {\n ctx: DataGridToolbarContext<TRow>;\n /** Extra content rendered inside the toolbar row, to the left of the\n * built-in columns / export actions. Use this to add table-specific\n * affordances (refresh, custom toggles, row counts) without giving up\n * the default actions. */\n extra?: React.ReactNode;\n /** Extra content rendered at the START of the toolbar row — occupies\n * the same position as the built-in quick search (after it, if the\n * quick search is visible). Use this together with `hideQuickSearch`\n * to fully replace the quick search with a custom input, e.g. an\n * AI-powered search bar. */\n extraLeading?: React.ReactNode;\n /** Whether to hide the built-in quick-search input. When `true`,\n * callers are expected to provide their own search UI via\n * `extraLeading`. */\n hideQuickSearch?: boolean;\n}) {\n const { state, onChange, columns, strings, exportCsv } = ctx;\n\n const columnPopover = usePopover();\n\n const updateVisibility = useCallback(\n (visibility: Record<string, boolean>) => {\n onChange((s) => ({ ...s, columnVisibility: visibility }));\n },\n [onChange],\n );\n\n const updateDateDisplay = useCallback(\n (mode: DataGridDateDisplay) => {\n onChange((s) => ({ ...s, dateDisplay: mode }));\n },\n [onChange],\n );\n\n const updateQuickSearch = useCallback(\n (value: string) => {\n onChange((s) => ({\n ...s,\n quickSearch: value,\n // Reset to first page whenever the search text changes,\n // otherwise you can end up on a page index that no longer\n // exists in the filtered / refetched result set.\n pagination: { ...s.pagination, pageIndex: 0 },\n }));\n },\n [onChange],\n );\n\n const hasDateColumns = useMemo(\n () => columns.some((c) => c.type === \"date\" || c.type === \"dateTime\"),\n [columns],\n );\n\n return (\n <div className=\"flex w-full min-w-0 flex-col gap-2 px-2.5 py-2.5 border-b border-foreground/[0.06] sm:flex-row sm:items-center sm:gap-2\">\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\">\n {!hideQuickSearch && (\n <QuickSearch\n value={state.quickSearch}\n onChange={updateQuickSearch}\n placeholder={strings.searchPlaceholder}\n />\n )}\n {extraLeading}\n {extra}\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-2\">\n <div className=\"relative shrink-0\" ref={columnPopover.ref}>\n <ToolbarButton\n onClick={() => columnPopover.setOpen(!columnPopover.open)}\n active={columnPopover.open}\n title={strings.columns}\n >\n <Eye className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n {columnPopover.open && (\n <PopoverPanel popoverRef={columnPopover.ref} className=\"right-0 left-auto\">\n <ColumnManager\n columns={columns}\n visibility={state.columnVisibility}\n onChange={updateVisibility}\n strings={strings}\n dateDisplay={state.dateDisplay}\n onDateDisplayChange={updateDateDisplay}\n hasDateColumns={hasDateColumns}\n />\n </PopoverPanel>\n )}\n </div>\n\n <ToolbarButton onClick={exportCsv} title={strings.export}>\n <DownloadSimple className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|