@acronis-platform/ui-react 0.58.0 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/components/ui/area-chart/area-chart.js +91 -63
  2. package/dist/components/ui/area-chart/area-chart.js.map +1 -1
  3. package/dist/components/ui/bar-chart/bar-chart.js +104 -73
  4. package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
  5. package/dist/components/ui/calendar/calendar.js +17 -15
  6. package/dist/components/ui/calendar/calendar.js.map +1 -1
  7. package/dist/components/ui/carousel-dialog/carousel-dialog.js +87 -0
  8. package/dist/components/ui/carousel-dialog/carousel-dialog.js.map +1 -0
  9. package/dist/components/ui/category-bar/category-bar.js +126 -0
  10. package/dist/components/ui/category-bar/category-bar.js.map +1 -0
  11. package/dist/components/ui/chart/chart-format.js +40 -0
  12. package/dist/components/ui/chart/chart-format.js.map +1 -0
  13. package/dist/components/ui/chart/chart.js.map +1 -1
  14. package/dist/components/ui/composed-chart/composed-chart.js +91 -63
  15. package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
  16. package/dist/components/ui/confidence-cone/confidence-cone.js +113 -85
  17. package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
  18. package/dist/components/ui/dialog/dialog.js +29 -29
  19. package/dist/components/ui/dialog/dialog.js.map +1 -1
  20. package/dist/components/ui/dialog-footer-carousel/dialog-footer-carousel.js +57 -0
  21. package/dist/components/ui/dialog-footer-carousel/dialog-footer-carousel.js.map +1 -0
  22. package/dist/components/ui/dialog-footer-default/dialog-footer-default.js +1 -1
  23. package/dist/components/ui/dialog-footer-default/dialog-footer-default.js.map +1 -1
  24. package/dist/components/ui/dialog-welcome/dialog-welcome.js +272 -0
  25. package/dist/components/ui/dialog-welcome/dialog-welcome.js.map +1 -0
  26. package/dist/components/ui/histogram/histogram.js +89 -61
  27. package/dist/components/ui/histogram/histogram.js.map +1 -1
  28. package/dist/components/ui/input/input.js.map +1 -1
  29. package/dist/components/ui/line-chart/line-chart.js +120 -92
  30. package/dist/components/ui/line-chart/line-chart.js.map +1 -1
  31. package/dist/components/ui/sankey-chart/sankey-chart.js +192 -0
  32. package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -0
  33. package/dist/components/ui/scatter-chart/scatter-chart.js +79 -51
  34. package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
  35. package/dist/components/ui/toolbar/toolbar.js +82 -92
  36. package/dist/components/ui/toolbar/toolbar.js.map +1 -1
  37. package/dist/index.js +461 -439
  38. package/dist/index.js.map +1 -1
  39. package/dist/lib/breakpoints.js +9 -6
  40. package/dist/lib/breakpoints.js.map +1 -1
  41. package/dist/node_modules/.pnpm/embla-carousel-react@8.6.0_react@19.2.6/node_modules/embla-carousel-react/esm/embla-carousel-react.esm.js +25 -0
  42. package/dist/node_modules/.pnpm/embla-carousel-react@8.6.0_react@19.2.6/node_modules/embla-carousel-react/esm/embla-carousel-react.esm.js.map +1 -0
  43. package/dist/node_modules/.pnpm/embla-carousel-reactive-utils@8.6.0_embla-carousel@8.6.0/node_modules/embla-carousel-reactive-utils/esm/embla-carousel-reactive-utils.esm.js +36 -0
  44. package/dist/node_modules/.pnpm/embla-carousel-reactive-utils@8.6.0_embla-carousel@8.6.0/node_modules/embla-carousel-reactive-utils/esm/embla-carousel-reactive-utils.esm.js.map +1 -0
  45. package/dist/node_modules/.pnpm/embla-carousel@8.6.0/node_modules/embla-carousel/esm/embla-carousel.esm.js +1205 -0
  46. package/dist/node_modules/.pnpm/embla-carousel@8.6.0/node_modules/embla-carousel/esm/embla-carousel.esm.js.map +1 -0
  47. package/dist/react.js +461 -439
  48. package/dist/react.js.map +1 -1
  49. package/dist/src/components/ui/area-chart/area-chart.d.ts +2 -17
  50. package/dist/src/components/ui/bar-chart/bar-chart.d.ts +2 -17
  51. package/dist/src/components/ui/carousel-dialog/carousel-dialog.d.ts +28 -0
  52. package/dist/src/components/ui/carousel-dialog/index.d.ts +1 -0
  53. package/dist/src/components/ui/category-bar/category-bar.d.ts +51 -0
  54. package/dist/src/components/ui/category-bar/index.d.ts +1 -0
  55. package/dist/src/components/ui/chart/__tests__/chart-format.test.d.ts +1 -0
  56. package/dist/src/components/ui/chart/chart-format.d.ts +111 -0
  57. package/dist/src/components/ui/chart/chart.d.ts +2 -0
  58. package/dist/src/components/ui/chart/index.d.ts +3 -1
  59. package/dist/src/components/ui/composed-chart/composed-chart.d.ts +2 -17
  60. package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +2 -19
  61. package/dist/src/components/ui/dialog-footer-carousel/dialog-footer-carousel.d.ts +9 -0
  62. package/dist/src/components/ui/dialog-footer-carousel/index.d.ts +1 -0
  63. package/dist/src/components/ui/dialog-welcome/dialog-welcome.d.ts +54 -0
  64. package/dist/src/components/ui/dialog-welcome/dialog-welcome.docs.d.ts +55 -0
  65. package/dist/src/components/ui/dialog-welcome/index.d.ts +1 -0
  66. package/dist/src/components/ui/histogram/histogram.d.ts +2 -17
  67. package/dist/src/components/ui/line-chart/line-chart.d.ts +2 -17
  68. package/dist/src/components/ui/sankey-chart/index.d.ts +2 -0
  69. package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +69 -0
  70. package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +2 -17
  71. package/dist/src/index.d.ts +5 -0
  72. package/dist/ui-react.css +1 -1
  73. package/package.json +5 -4
@@ -1,4 +1,4 @@
1
- import { jsx as o } from "react/jsx-runtime";
1
+ import { jsx as a } from "react/jsx-runtime";
2
2
  import * as c from "react";
3
3
  import { ChevronLeftIcon as p, ChevronRightIcon as m, ChevronDownIcon as f } from "@acronis-platform/icons-react/stroke-mono";
4
4
  import { cn as r } from "../../../lib/utils.js";
@@ -94,7 +94,7 @@ function x(n, e) {
94
94
  };
95
95
  }
96
96
  const h = {
97
- Root: ({ className: n, rootRef: e, ...t }) => /* @__PURE__ */ o(
97
+ Root: ({ className: n, rootRef: e, ...t }) => /* @__PURE__ */ a(
98
98
  "div",
99
99
  {
100
100
  "data-slot": "calendar",
@@ -103,29 +103,31 @@ const h = {
103
103
  ...t
104
104
  }
105
105
  ),
106
- Chevron: ({ className: n, orientation: e, ...t }) => e === "left" ? /* @__PURE__ */ o(
106
+ // Drop react-day-picker's numeric `size` — these chevrons render at the
107
+ // fixed design size (16); icons-react's `size` is the 16|24 design axis.
108
+ Chevron: ({ className: n, orientation: e, size: t, ...o }) => e === "left" ? /* @__PURE__ */ a(
107
109
  p,
108
110
  {
109
111
  size: 16,
110
112
  className: r("rtl:rotate-180", n),
111
- ...t
113
+ ...o
112
114
  }
113
- ) : e === "right" ? /* @__PURE__ */ o(
115
+ ) : e === "right" ? /* @__PURE__ */ a(
114
116
  m,
115
117
  {
116
118
  size: 16,
117
119
  className: r("rtl:rotate-180", n),
118
- ...t
120
+ ...o
119
121
  }
120
- ) : /* @__PURE__ */ o(f, { size: 16, className: r(n), ...t }),
122
+ ) : /* @__PURE__ */ a(f, { size: 16, className: r(n), ...o }),
121
123
  DayButton: y,
122
- WeekNumber: ({ children: n, ...e }) => /* @__PURE__ */ o("td", { ...e, children: /* @__PURE__ */ o("div", { className: "flex size-[var(--cell-size)] items-center justify-center text-center", children: n }) })
124
+ WeekNumber: ({ children: n, ...e }) => /* @__PURE__ */ a("td", { ...e, children: /* @__PURE__ */ a("div", { className: "flex size-[var(--cell-size)] items-center justify-center text-center", children: n }) })
123
125
  };
124
126
  function D({
125
127
  className: n,
126
128
  classNames: e,
127
129
  showOutsideDays: t = !0,
128
- captionLayout: a = "label",
130
+ captionLayout: o = "label",
129
131
  // Default the grid to a Monday week start (0=Sun..6=Sat); consumers can still
130
132
  // override per instance.
131
133
  weekStartsOn: u = 1,
@@ -134,7 +136,7 @@ function D({
134
136
  ...s
135
137
  }) {
136
138
  const g = l();
137
- return /* @__PURE__ */ o(
139
+ return /* @__PURE__ */ a(
138
140
  v,
139
141
  {
140
142
  showOutsideDays: t,
@@ -143,13 +145,13 @@ function D({
143
145
  "group/calendar bg-background p-3 [--cell-size:2rem] [[data-slot=popover-content]_&]:bg-transparent",
144
146
  n
145
147
  ),
146
- captionLayout: a,
148
+ captionLayout: o,
147
149
  formatters: {
148
150
  formatMonthDropdown: (b) => b.toLocaleString("default", { month: "short" }),
149
151
  ...d
150
152
  },
151
153
  classNames: {
152
- ...x(a, g),
154
+ ...x(o, g),
153
155
  ...e
154
156
  },
155
157
  components: {
@@ -164,13 +166,13 @@ function y({
164
166
  className: n,
165
167
  day: e,
166
168
  modifiers: t,
167
- ...a
169
+ ...o
168
170
  }) {
169
171
  const u = l(), d = c.useRef(null);
170
172
  return c.useEffect(() => {
171
173
  var i;
172
174
  t.focused && ((i = d.current) == null || i.focus());
173
- }, [t.focused]), /* @__PURE__ */ o(
175
+ }, [t.focused]), /* @__PURE__ */ a(
174
176
  "button",
175
177
  {
176
178
  ref: d,
@@ -193,7 +195,7 @@ function y({
193
195
  u.day,
194
196
  n
195
197
  ),
196
- ...a
198
+ ...o
197
199
  }
198
200
  );
199
201
  }
@@ -1 +1 @@
1
- {"version":3,"file":"calendar.js","sources":["../../../../src/components/ui/calendar/calendar.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n ChevronDownIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n} from '@acronis-platform/icons-react/stroke-mono';\nimport {\n DayButton,\n DayPicker,\n getDefaultClassNames,\n type ClassNames,\n type CustomComponents,\n} from 'react-day-picker';\n\nimport { cn } from '@/lib/utils';\n\n// Ported from `@acronis-platform/shadcn-uikit`'s `calendar`\n// (packages/ui-legacy/src/components/ui/calendar.tsx). A pure day-grid built on\n// `react-day-picker`'s `DayPicker` — single / range / multiple selection and one\n// or more months side by side (`numberOfMonths`), with the prev/next chevrons at\n// the outer edges of the month row. No `--ui-calendar-*` token tier exists yet, so\n// this design-pending v1 themes off the shared semantic vocabulary:\n// • surface / text -> bg-background / text-foreground\n// • selected day + range endpoints -> --ui-background-brand-primary + --ui-glyph-on-brand-primary\n// • range-middle highlight -> --ui-background-surface-hover (`bg-accent`)\n// • hover -> bg-accent / text-accent-foreground\n// • today -> font-weight + underline (no color dependency)\n// • outside-month / muted -> text-muted-foreground (--ui-text-on-surface-secondary)\n// • disabled days -> --ui-text-on-surface-disabled\n// • focus ring -> --ui-focus-primary\n// Reconcile (and a possible `--ui-calendar-*` tier) with\n// `/figma-component Calendar <url> --update` once mockups land.\n//\n// Why plain `<button>` for day cells AND nav chevrons (not `Button` / `ButtonIcon`):\n// • Day cells are a dense text grid, not icon buttons. `Button` is a fixed\n// 32px-tall pill with a 64px min-width, per-variant px, and (for `ghost`) a\n// hover underline — none of which suit a square, borderless day cell. There\n// is no `size`/`square` key on `buttonVariants` to opt out of that geometry,\n// and adding one purely for the calendar would contort Button's API for a\n// one-off. `ButtonIcon` is icon-only and force-sizes its glyph to 24px\n// (`--ui-button-icon-global-icon-size`), so it cannot host day-number text.\n// • Nav chevrons look closest to `ButtonIcon` (ghost, 32px square) but adopting\n// it here is a net contortion: (1) `react-day-picker`'s Nav marks the edge\n// buttons with `aria-disabled`, while `ButtonIcon`'s disabled treatment +\n// `pointer-events-none` key off the `disabled` attribute — the disabled state\n// would never paint; (2) `ButtonIcon` force-sizes the glyph to 24px, but the\n// nav chevrons are 16px. Both would require overriding ButtonIcon internals,\n// so plain `<button>` with `aria-disabled:` variants is the honest fit until a\n// tokened `--ui-calendar-*` tier defines these controls.\n\nexport type CalendarProps = React.ComponentProps<typeof DayPicker>;\n\n// The full `classNames` map, static aside from the one `captionLayout`-dependent\n// branch (the boxed vs. dropdown caption treatment) and the per-key merge with\n// `react-day-picker`'s own `getDefaultClassNames()`. Built once per render and\n// merged with any caller `classNames` override at the call site.\nfunction buildCalendarClassNames(\n captionLayout: CalendarProps['captionLayout'],\n defaultClassNames: ClassNames\n): Partial<ClassNames> {\n return {\n root: cn('w-fit', defaultClassNames.root),\n months: cn(\n 'relative flex flex-col gap-4 md:flex-row',\n defaultClassNames.months\n ),\n month: cn('flex w-full flex-col gap-4', defaultClassNames.month),\n nav: cn(\n 'absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1',\n defaultClassNames.nav\n ),\n button_previous: cn(\n 'inline-flex size-[var(--cell-size)] cursor-pointer select-none items-center justify-center rounded-md p-0 text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-[var(--ui-focus-primary)] aria-disabled:pointer-events-none aria-disabled:text-[var(--ui-text-on-surface-disabled)]',\n defaultClassNames.button_previous\n ),\n button_next: cn(\n 'inline-flex size-[var(--cell-size)] cursor-pointer select-none items-center justify-center rounded-md p-0 text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-[var(--ui-focus-primary)] aria-disabled:pointer-events-none aria-disabled:text-[var(--ui-text-on-surface-disabled)]',\n defaultClassNames.button_next\n ),\n month_caption: cn(\n 'flex h-[var(--cell-size)] w-full items-center justify-center px-[var(--cell-size)]',\n defaultClassNames.month_caption\n ),\n dropdowns: cn(\n 'flex h-[var(--cell-size)] w-full items-center justify-center gap-1.5 text-sm font-medium',\n defaultClassNames.dropdowns\n ),\n dropdown_root: cn(\n 'relative rounded-md border border-border has-focus:border-[var(--ui-border-on-surface-border-active)] has-focus:ring-[3px] has-focus:ring-[var(--ui-focus-primary)]',\n defaultClassNames.dropdown_root\n ),\n dropdown: cn(\n // The invisible native <select> overlays the whole `dropdown_root`\n // box, so its cursor drives the caption box's hover cursor — pointer,\n // to read as the interactive dropdown trigger it is (vs the plain,\n // non-clickable `caption_label` box in `captionLayout=\"label\"`).\n 'absolute inset-0 cursor-pointer bg-background opacity-0',\n defaultClassNames.dropdown\n ),\n caption_label: cn(\n 'select-none font-medium',\n captionLayout === 'label'\n ? // Boxed caption (`[ July 2026 ]`) — reuses `dropdown_root`'s\n // border/rounded box treatment so the label and dropdown layouts\n // read as the same control.\n 'rounded-md border border-border px-3 py-1 text-sm'\n : 'flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground',\n defaultClassNames.caption_label\n ),\n month_grid: cn('w-full border-collapse', defaultClassNames.month_grid),\n weekdays: cn('flex', defaultClassNames.weekdays),\n weekday: cn(\n 'flex-1 select-none rounded-md text-[0.8rem] font-normal text-muted-foreground',\n defaultClassNames.weekday\n ),\n week: cn('mt-2 flex w-full', defaultClassNames.week),\n week_number_header: cn(\n 'w-[var(--cell-size)] select-none',\n defaultClassNames.week_number_header\n ),\n week_number: cn(\n 'select-none text-[0.8rem] text-muted-foreground',\n defaultClassNames.week_number\n ),\n day: cn(\n // Logical (`-s-`/`-e-`) corner rounding so the range band's outer\n // corners flip sides under RTL along with the CSS-reversed grid.\n 'group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-s-md [&:last-child[data-selected=true]_button]:rounded-e-md',\n defaultClassNames.day\n ),\n range_start: cn('rounded-s-md', defaultClassNames.range_start),\n range_middle: cn('rounded-none bg-accent', defaultClassNames.range_middle),\n range_end: cn('rounded-e-md', defaultClassNames.range_end),\n today: cn(\n 'rounded-md font-semibold underline data-[selected=true]:rounded-none data-[selected=true]:no-underline',\n defaultClassNames.today\n ),\n outside: cn(\n 'text-muted-foreground aria-selected:text-muted-foreground',\n defaultClassNames.outside\n ),\n disabled: cn(\n 'text-[var(--ui-text-on-surface-disabled)]',\n defaultClassNames.disabled\n ),\n hidden: cn('invisible', defaultClassNames.hidden),\n };\n}\n\n// The component-override map. Fully static (no prop/state dependency), so it lives\n// at module scope and is merged with any caller `components` override at the call\n// site. `Chevron`'s RTL flip keys off the `rtl:` variant, so it needs no props.\nconst calendarComponents: Partial<CustomComponents> = {\n Root: ({ className, rootRef, ...props }) => (\n <div\n data-slot=\"calendar\"\n ref={rootRef}\n className={cn(className)}\n {...props}\n />\n ),\n Chevron: ({ className, orientation, ...props }) => {\n // Mirror the horizontal nav chevrons under RTL — `react-day-picker`\n // hardcodes orientation \"left\"/\"right\" for previous/next regardless of\n // direction, so we flip them ourselves. Applied on the icon we own via\n // the `rtl:` variant ([dir=rtl] ancestor), so it's robust to rdp's\n // internal class names. The vertical (dropdown) chevron never flips.\n if (orientation === 'left') {\n return (\n <ChevronLeftIcon\n size={16}\n className={cn('rtl:rotate-180', className)}\n {...props}\n />\n );\n }\n if (orientation === 'right') {\n return (\n <ChevronRightIcon\n size={16}\n className={cn('rtl:rotate-180', className)}\n {...props}\n />\n );\n }\n return <ChevronDownIcon size={16} className={cn(className)} {...props} />;\n },\n DayButton: CalendarDayButton,\n WeekNumber: ({ children, ...props }) => (\n <td {...props}>\n <div className=\"flex size-[var(--cell-size)] items-center justify-center text-center\">\n {children}\n </div>\n </td>\n ),\n};\n\nfunction Calendar({\n className,\n classNames,\n showOutsideDays = true,\n captionLayout = 'label',\n // Default the grid to a Monday week start (0=Sun..6=Sat); consumers can still\n // override per instance.\n weekStartsOn = 1,\n formatters,\n components,\n ...props\n}: CalendarProps) {\n const defaultClassNames = getDefaultClassNames();\n\n return (\n <DayPicker\n showOutsideDays={showOutsideDays}\n weekStartsOn={weekStartsOn}\n className={cn(\n 'group/calendar bg-background p-3 [--cell-size:2rem] [[data-slot=popover-content]_&]:bg-transparent',\n className\n )}\n captionLayout={captionLayout}\n formatters={{\n formatMonthDropdown: (date) =>\n date.toLocaleString('default', { month: 'short' }),\n ...formatters,\n }}\n classNames={{\n ...buildCalendarClassNames(captionLayout, defaultClassNames),\n ...classNames,\n }}\n components={{\n ...calendarComponents,\n ...components,\n }}\n {...props}\n />\n );\n}\n\nfunction CalendarDayButton({\n className,\n day,\n modifiers,\n ...props\n}: React.ComponentProps<typeof DayButton>) {\n const defaultClassNames = getDefaultClassNames();\n\n const ref = React.useRef<HTMLButtonElement>(null);\n React.useEffect(() => {\n if (modifiers.focused) ref.current?.focus();\n }, [modifiers.focused]);\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-day={day.date.toLocaleDateString()}\n data-selected-single={\n modifiers.selected &&\n !modifiers.range_start &&\n !modifiers.range_end &&\n !modifiers.range_middle\n }\n data-range-start={modifiers.range_start}\n data-range-end={modifiers.range_end}\n data-range-middle={modifiers.range_middle}\n className={cn(\n 'flex aspect-square size-[var(--cell-size)] w-full min-w-[var(--cell-size)] cursor-pointer flex-col items-center justify-center gap-1 rounded-md p-0 font-normal leading-none text-foreground outline-none transition-colors',\n 'hover:bg-accent hover:text-accent-foreground',\n 'data-[selected-single=true]:bg-[var(--ui-background-brand-primary)] data-[selected-single=true]:text-[var(--ui-glyph-on-brand-primary)] data-[selected-single=true]:hover:bg-[var(--ui-background-brand-primary-hover)]',\n 'data-[range-start=true]:rounded-md data-[range-start=true]:bg-[var(--ui-background-brand-primary)] data-[range-start=true]:text-[var(--ui-glyph-on-brand-primary)] data-[range-start=true]:hover:bg-[var(--ui-background-brand-primary-hover)]',\n 'data-[range-end=true]:rounded-md data-[range-end=true]:bg-[var(--ui-background-brand-primary)] data-[range-end=true]:text-[var(--ui-glyph-on-brand-primary)] data-[range-end=true]:hover:bg-[var(--ui-background-brand-primary-hover)]',\n 'data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground',\n 'group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-[var(--ui-focus-primary)]',\n 'disabled:pointer-events-none disabled:text-[var(--ui-text-on-surface-disabled)]',\n '[&>span]:text-xs [&>span]:opacity-70',\n defaultClassNames.day,\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Calendar, CalendarDayButton };\n"],"names":["buildCalendarClassNames","captionLayout","defaultClassNames","cn","calendarComponents","className","rootRef","props","jsx","orientation","ChevronLeftIcon","ChevronRightIcon","ChevronDownIcon","CalendarDayButton","children","Calendar","classNames","showOutsideDays","weekStartsOn","formatters","components","getDefaultClassNames","DayPicker","date","day","modifiers","ref","React","_a"],"mappings":"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"}
1
+ {"version":3,"file":"calendar.js","sources":["../../../../src/components/ui/calendar/calendar.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n ChevronDownIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n} from '@acronis-platform/icons-react/stroke-mono';\nimport {\n DayButton,\n DayPicker,\n getDefaultClassNames,\n type ClassNames,\n type CustomComponents,\n} from 'react-day-picker';\n\nimport { cn } from '@/lib/utils';\n\n// Ported from `@acronis-platform/shadcn-uikit`'s `calendar`\n// (packages/ui-legacy/src/components/ui/calendar.tsx). A pure day-grid built on\n// `react-day-picker`'s `DayPicker` — single / range / multiple selection and one\n// or more months side by side (`numberOfMonths`), with the prev/next chevrons at\n// the outer edges of the month row. No `--ui-calendar-*` token tier exists yet, so\n// this design-pending v1 themes off the shared semantic vocabulary:\n// • surface / text -> bg-background / text-foreground\n// • selected day + range endpoints -> --ui-background-brand-primary + --ui-glyph-on-brand-primary\n// • range-middle highlight -> --ui-background-surface-hover (`bg-accent`)\n// • hover -> bg-accent / text-accent-foreground\n// • today -> font-weight + underline (no color dependency)\n// • outside-month / muted -> text-muted-foreground (--ui-text-on-surface-secondary)\n// • disabled days -> --ui-text-on-surface-disabled\n// • focus ring -> --ui-focus-primary\n// Reconcile (and a possible `--ui-calendar-*` tier) with\n// `/figma-component Calendar <url> --update` once mockups land.\n//\n// Why plain `<button>` for day cells AND nav chevrons (not `Button` / `ButtonIcon`):\n// • Day cells are a dense text grid, not icon buttons. `Button` is a fixed\n// 32px-tall pill with a 64px min-width, per-variant px, and (for `ghost`) a\n// hover underline — none of which suit a square, borderless day cell. There\n// is no `size`/`square` key on `buttonVariants` to opt out of that geometry,\n// and adding one purely for the calendar would contort Button's API for a\n// one-off. `ButtonIcon` is icon-only and force-sizes its glyph to 24px\n// (`--ui-button-icon-global-icon-size`), so it cannot host day-number text.\n// • Nav chevrons look closest to `ButtonIcon` (ghost, 32px square) but adopting\n// it here is a net contortion: (1) `react-day-picker`'s Nav marks the edge\n// buttons with `aria-disabled`, while `ButtonIcon`'s disabled treatment +\n// `pointer-events-none` key off the `disabled` attribute — the disabled state\n// would never paint; (2) `ButtonIcon` force-sizes the glyph to 24px, but the\n// nav chevrons are 16px. Both would require overriding ButtonIcon internals,\n// so plain `<button>` with `aria-disabled:` variants is the honest fit until a\n// tokened `--ui-calendar-*` tier defines these controls.\n\nexport type CalendarProps = React.ComponentProps<typeof DayPicker>;\n\n// The full `classNames` map, static aside from the one `captionLayout`-dependent\n// branch (the boxed vs. dropdown caption treatment) and the per-key merge with\n// `react-day-picker`'s own `getDefaultClassNames()`. Built once per render and\n// merged with any caller `classNames` override at the call site.\nfunction buildCalendarClassNames(\n captionLayout: CalendarProps['captionLayout'],\n defaultClassNames: ClassNames\n): Partial<ClassNames> {\n return {\n root: cn('w-fit', defaultClassNames.root),\n months: cn(\n 'relative flex flex-col gap-4 md:flex-row',\n defaultClassNames.months\n ),\n month: cn('flex w-full flex-col gap-4', defaultClassNames.month),\n nav: cn(\n 'absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1',\n defaultClassNames.nav\n ),\n button_previous: cn(\n 'inline-flex size-[var(--cell-size)] cursor-pointer select-none items-center justify-center rounded-md p-0 text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-[var(--ui-focus-primary)] aria-disabled:pointer-events-none aria-disabled:text-[var(--ui-text-on-surface-disabled)]',\n defaultClassNames.button_previous\n ),\n button_next: cn(\n 'inline-flex size-[var(--cell-size)] cursor-pointer select-none items-center justify-center rounded-md p-0 text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-[var(--ui-focus-primary)] aria-disabled:pointer-events-none aria-disabled:text-[var(--ui-text-on-surface-disabled)]',\n defaultClassNames.button_next\n ),\n month_caption: cn(\n 'flex h-[var(--cell-size)] w-full items-center justify-center px-[var(--cell-size)]',\n defaultClassNames.month_caption\n ),\n dropdowns: cn(\n 'flex h-[var(--cell-size)] w-full items-center justify-center gap-1.5 text-sm font-medium',\n defaultClassNames.dropdowns\n ),\n dropdown_root: cn(\n 'relative rounded-md border border-border has-focus:border-[var(--ui-border-on-surface-border-active)] has-focus:ring-[3px] has-focus:ring-[var(--ui-focus-primary)]',\n defaultClassNames.dropdown_root\n ),\n dropdown: cn(\n // The invisible native <select> overlays the whole `dropdown_root`\n // box, so its cursor drives the caption box's hover cursor — pointer,\n // to read as the interactive dropdown trigger it is (vs the plain,\n // non-clickable `caption_label` box in `captionLayout=\"label\"`).\n 'absolute inset-0 cursor-pointer bg-background opacity-0',\n defaultClassNames.dropdown\n ),\n caption_label: cn(\n 'select-none font-medium',\n captionLayout === 'label'\n ? // Boxed caption (`[ July 2026 ]`) — reuses `dropdown_root`'s\n // border/rounded box treatment so the label and dropdown layouts\n // read as the same control.\n 'rounded-md border border-border px-3 py-1 text-sm'\n : 'flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground',\n defaultClassNames.caption_label\n ),\n month_grid: cn('w-full border-collapse', defaultClassNames.month_grid),\n weekdays: cn('flex', defaultClassNames.weekdays),\n weekday: cn(\n 'flex-1 select-none rounded-md text-[0.8rem] font-normal text-muted-foreground',\n defaultClassNames.weekday\n ),\n week: cn('mt-2 flex w-full', defaultClassNames.week),\n week_number_header: cn(\n 'w-[var(--cell-size)] select-none',\n defaultClassNames.week_number_header\n ),\n week_number: cn(\n 'select-none text-[0.8rem] text-muted-foreground',\n defaultClassNames.week_number\n ),\n day: cn(\n // Logical (`-s-`/`-e-`) corner rounding so the range band's outer\n // corners flip sides under RTL along with the CSS-reversed grid.\n 'group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-s-md [&:last-child[data-selected=true]_button]:rounded-e-md',\n defaultClassNames.day\n ),\n range_start: cn('rounded-s-md', defaultClassNames.range_start),\n range_middle: cn('rounded-none bg-accent', defaultClassNames.range_middle),\n range_end: cn('rounded-e-md', defaultClassNames.range_end),\n today: cn(\n 'rounded-md font-semibold underline data-[selected=true]:rounded-none data-[selected=true]:no-underline',\n defaultClassNames.today\n ),\n outside: cn(\n 'text-muted-foreground aria-selected:text-muted-foreground',\n defaultClassNames.outside\n ),\n disabled: cn(\n 'text-[var(--ui-text-on-surface-disabled)]',\n defaultClassNames.disabled\n ),\n hidden: cn('invisible', defaultClassNames.hidden),\n };\n}\n\n// The component-override map. Fully static (no prop/state dependency), so it lives\n// at module scope and is merged with any caller `components` override at the call\n// site. `Chevron`'s RTL flip keys off the `rtl:` variant, so it needs no props.\nconst calendarComponents: Partial<CustomComponents> = {\n Root: ({ className, rootRef, ...props }) => (\n <div\n data-slot=\"calendar\"\n ref={rootRef}\n className={cn(className)}\n {...props}\n />\n ),\n // Drop react-day-picker's numeric `size` — these chevrons render at the\n // fixed design size (16); icons-react's `size` is the 16|24 design axis.\n Chevron: ({ className, orientation, size: _size, ...props }) => {\n // Mirror the horizontal nav chevrons under RTL — `react-day-picker`\n // hardcodes orientation \"left\"/\"right\" for previous/next regardless of\n // direction, so we flip them ourselves. Applied on the icon we own via\n // the `rtl:` variant ([dir=rtl] ancestor), so it's robust to rdp's\n // internal class names. The vertical (dropdown) chevron never flips.\n if (orientation === 'left') {\n return (\n <ChevronLeftIcon\n size={16}\n className={cn('rtl:rotate-180', className)}\n {...props}\n />\n );\n }\n if (orientation === 'right') {\n return (\n <ChevronRightIcon\n size={16}\n className={cn('rtl:rotate-180', className)}\n {...props}\n />\n );\n }\n return <ChevronDownIcon size={16} className={cn(className)} {...props} />;\n },\n DayButton: CalendarDayButton,\n WeekNumber: ({ children, ...props }) => (\n <td {...props}>\n <div className=\"flex size-[var(--cell-size)] items-center justify-center text-center\">\n {children}\n </div>\n </td>\n ),\n};\n\nfunction Calendar({\n className,\n classNames,\n showOutsideDays = true,\n captionLayout = 'label',\n // Default the grid to a Monday week start (0=Sun..6=Sat); consumers can still\n // override per instance.\n weekStartsOn = 1,\n formatters,\n components,\n ...props\n}: CalendarProps) {\n const defaultClassNames = getDefaultClassNames();\n\n return (\n <DayPicker\n showOutsideDays={showOutsideDays}\n weekStartsOn={weekStartsOn}\n className={cn(\n 'group/calendar bg-background p-3 [--cell-size:2rem] [[data-slot=popover-content]_&]:bg-transparent',\n className\n )}\n captionLayout={captionLayout}\n formatters={{\n formatMonthDropdown: (date) =>\n date.toLocaleString('default', { month: 'short' }),\n ...formatters,\n }}\n classNames={{\n ...buildCalendarClassNames(captionLayout, defaultClassNames),\n ...classNames,\n }}\n components={{\n ...calendarComponents,\n ...components,\n }}\n {...props}\n />\n );\n}\n\nfunction CalendarDayButton({\n className,\n day,\n modifiers,\n ...props\n}: React.ComponentProps<typeof DayButton>) {\n const defaultClassNames = getDefaultClassNames();\n\n const ref = React.useRef<HTMLButtonElement>(null);\n React.useEffect(() => {\n if (modifiers.focused) ref.current?.focus();\n }, [modifiers.focused]);\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-day={day.date.toLocaleDateString()}\n data-selected-single={\n modifiers.selected &&\n !modifiers.range_start &&\n !modifiers.range_end &&\n !modifiers.range_middle\n }\n data-range-start={modifiers.range_start}\n data-range-end={modifiers.range_end}\n data-range-middle={modifiers.range_middle}\n className={cn(\n 'flex aspect-square size-[var(--cell-size)] w-full min-w-[var(--cell-size)] cursor-pointer flex-col items-center justify-center gap-1 rounded-md p-0 font-normal leading-none text-foreground outline-none transition-colors',\n 'hover:bg-accent hover:text-accent-foreground',\n 'data-[selected-single=true]:bg-[var(--ui-background-brand-primary)] data-[selected-single=true]:text-[var(--ui-glyph-on-brand-primary)] data-[selected-single=true]:hover:bg-[var(--ui-background-brand-primary-hover)]',\n 'data-[range-start=true]:rounded-md data-[range-start=true]:bg-[var(--ui-background-brand-primary)] data-[range-start=true]:text-[var(--ui-glyph-on-brand-primary)] data-[range-start=true]:hover:bg-[var(--ui-background-brand-primary-hover)]',\n 'data-[range-end=true]:rounded-md data-[range-end=true]:bg-[var(--ui-background-brand-primary)] data-[range-end=true]:text-[var(--ui-glyph-on-brand-primary)] data-[range-end=true]:hover:bg-[var(--ui-background-brand-primary-hover)]',\n 'data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground',\n 'group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-[var(--ui-focus-primary)]',\n 'disabled:pointer-events-none disabled:text-[var(--ui-text-on-surface-disabled)]',\n '[&>span]:text-xs [&>span]:opacity-70',\n defaultClassNames.day,\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Calendar, CalendarDayButton };\n"],"names":["buildCalendarClassNames","captionLayout","defaultClassNames","cn","calendarComponents","className","rootRef","props","jsx","orientation","_size","ChevronLeftIcon","ChevronRightIcon","ChevronDownIcon","CalendarDayButton","children","Calendar","classNames","showOutsideDays","weekStartsOn","formatters","components","getDefaultClassNames","DayPicker","date","day","modifiers","ref","React","_a"],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import { jsxs as k, jsx as i } from "react/jsx-runtime";
2
+ import * as x from "react";
3
+ import { cn as a } from "../../../lib/utils.js";
4
+ import { Button as f } from "../button/button.js";
5
+ const j = (e, r) => `Go to slide ${e + 1} of ${r}`, w = x.forwardRef(
6
+ ({
7
+ className: e,
8
+ variant: r = "first",
9
+ slideCount: t = 1,
10
+ selectedIndex: u = 0,
11
+ onSelectIndex: l,
12
+ onBack: m,
13
+ onNext: d,
14
+ onPrimaryAction: p,
15
+ backLabel: h = "Back",
16
+ nextLabel: v = "Next",
17
+ primaryLabel: b = "Call to action",
18
+ goToSlideLabel: g = j,
19
+ ...y
20
+ }, N) => {
21
+ const o = r === "first", c = r === "last";
22
+ return /* @__PURE__ */ k(
23
+ "div",
24
+ {
25
+ ref: N,
26
+ className: a(
27
+ "flex h-8 w-full items-center justify-between",
28
+ e
29
+ ),
30
+ ...y,
31
+ children: [
32
+ /* @__PURE__ */ i(
33
+ "div",
34
+ {
35
+ className: a(
36
+ "flex min-w-0 flex-1 flex-col items-start justify-center",
37
+ o && "h-8"
38
+ ),
39
+ children: !o && /* @__PURE__ */ i(f, { variant: "secondary", onClick: m, children: h })
40
+ }
41
+ ),
42
+ /* @__PURE__ */ i(
43
+ "div",
44
+ {
45
+ className: "flex shrink-0 items-center gap-[var(--ui-carousel-dialog-list-indicator-gap)]",
46
+ children: Array.from({ length: t }, (C, s) => {
47
+ const n = s === u;
48
+ return /* @__PURE__ */ i(
49
+ "button",
50
+ {
51
+ type: "button",
52
+ "aria-current": n || void 0,
53
+ "aria-label": g(s, t),
54
+ onClick: () => l == null ? void 0 : l(s),
55
+ className: "relative block size-4 shrink-0 cursor-pointer rounded-full outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-focus-primary)]",
56
+ children: /* @__PURE__ */ i(
57
+ "span",
58
+ {
59
+ className: a(
60
+ "absolute inset-[3.2px] rounded-full",
61
+ n ? "bg-[var(--ui-glyph-on-surface-primary)]" : "bg-[var(--ui-glyph-on-surface-disabled)]"
62
+ )
63
+ }
64
+ )
65
+ },
66
+ s
67
+ );
68
+ })
69
+ }
70
+ ),
71
+ /* @__PURE__ */ i(
72
+ "div",
73
+ {
74
+ className: "flex min-w-0 flex-1 flex-col items-end justify-center",
75
+ children: /* @__PURE__ */ i(f, { onClick: c ? p : d, children: c ? b : v })
76
+ }
77
+ )
78
+ ]
79
+ }
80
+ );
81
+ }
82
+ );
83
+ w.displayName = "CarouselDialog";
84
+ export {
85
+ w as CarouselDialog
86
+ };
87
+ //# sourceMappingURL=carousel-dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carousel-dialog.js","sources":["../../../../src/components/ui/carousel-dialog/carousel-dialog.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '@/lib/utils';\n\nimport { Button } from '../button';\n\n// Ports Figma's \"CarouselDialog\" component (node 6353:5864's descendant,\n// isolated at 6353:4718 / 6353:4891 / 6353:4922 for the first/middle/last\n// variants): the row of controls inside a `DialogFooterCarousel` — a `Back`\n// button (`boxLeft`, hidden on the first slide), the dot `ListIndicator`, and\n// a `Next`/call-to-action button (`boxRight`). Pure controls — no Embla import\n// here; the slide count/index/callbacks are threaded down from\n// `DialogWelcome`, which owns the carousel engine.\n//\n// Internal only — not exported from the package's public entry point. Apps\n// building a welcome/onboarding carousel dialog should use `DialogWelcome`.\n\nexport type CarouselDialogVariant = 'first' | 'middle' | 'last';\n\nexport interface CarouselDialogProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n /** Which slide position this renders for. Defaults to `'first'`. */\n variant?: CarouselDialogVariant;\n /** Total number of slides, used to render the dot `ListIndicator`. Defaults to `1`. */\n slideCount?: number;\n /** The currently active slide index (0-based). Defaults to `0`. */\n selectedIndex?: number;\n /** Fires when a dot is activated, with the dot's slide index. */\n onSelectIndex?: (index: number) => void;\n /** Fires when `Back` (hidden on `variant=\"first\"`) is activated. */\n onBack?: () => void;\n /** Fires when `Next` (`variant=\"first\" | \"middle\"`) is activated. */\n onNext?: () => void;\n /** Fires when the call-to-action button (`variant=\"last\"`) is activated. */\n onPrimaryAction?: () => void;\n /** `Back` button label. Defaults to `'Back'`. */\n backLabel?: string;\n /** `Next` button label (`variant=\"first\" | \"middle\"`). Defaults to `'Next'`. */\n nextLabel?: string;\n /** Call-to-action button label (`variant=\"last\"`). Defaults to `'Call to action'`. */\n primaryLabel?: string;\n /** Builds each dot's accessible name from its 0-based index and the slide count. */\n goToSlideLabel?: (index: number, count: number) => string;\n}\n\nconst defaultGoToSlideLabel = (index: number, count: number) =>\n `Go to slide ${index + 1} of ${count}`;\n\nconst CarouselDialog = React.forwardRef<HTMLDivElement, CarouselDialogProps>(\n (\n {\n className,\n variant = 'first',\n slideCount = 1,\n selectedIndex = 0,\n onSelectIndex,\n onBack,\n onNext,\n onPrimaryAction,\n backLabel = 'Back',\n nextLabel = 'Next',\n primaryLabel = 'Call to action',\n goToSlideLabel = defaultGoToSlideLabel,\n ...props\n },\n ref\n ) => {\n const isFirst = variant === 'first';\n const isLast = variant === 'last';\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex h-8 w-full items-center justify-between',\n className\n )}\n {...props}\n >\n <div\n className={cn(\n 'flex min-w-0 flex-1 flex-col items-start justify-center',\n isFirst && 'h-8'\n )}\n >\n {!isFirst && (\n <Button variant=\"secondary\" onClick={onBack}>\n {backLabel}\n </Button>\n )}\n </div>\n\n <div\n className=\"flex shrink-0 items-center gap-[var(--ui-carousel-dialog-list-indicator-gap)]\"\n >\n {Array.from({ length: slideCount }, (_, index) => {\n const isActive = index === selectedIndex;\n return (\n <button\n key={index}\n type=\"button\"\n aria-current={isActive || undefined}\n aria-label={goToSlideLabel(index, slideCount)}\n onClick={() => onSelectIndex?.(index)}\n className=\"relative block size-4 shrink-0 cursor-pointer rounded-full outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-focus-primary)]\"\n >\n <span\n className={cn(\n 'absolute inset-[3.2px] rounded-full',\n isActive\n ? 'bg-[var(--ui-glyph-on-surface-primary)]'\n : 'bg-[var(--ui-glyph-on-surface-disabled)]'\n )}\n />\n </button>\n );\n })}\n </div>\n\n <div\n className=\"flex min-w-0 flex-1 flex-col items-end justify-center\"\n >\n <Button onClick={isLast ? onPrimaryAction : onNext}>\n {isLast ? primaryLabel : nextLabel}\n </Button>\n </div>\n </div>\n );\n }\n);\nCarouselDialog.displayName = 'CarouselDialog';\n\nexport { CarouselDialog };\n"],"names":["defaultGoToSlideLabel","index","count","CarouselDialog","React","className","variant","slideCount","selectedIndex","onSelectIndex","onBack","onNext","onPrimaryAction","backLabel","nextLabel","primaryLabel","goToSlideLabel","props","ref","isFirst","isLast","jsxs","cn","jsx","Button","_","isActive"],"mappings":";;;;AA6CA,MAAMA,IAAwB,CAACC,GAAeC,MAC5C,eAAeD,IAAQ,CAAC,OAAOC,CAAK,IAEhCC,IAAiBC,EAAM;AAAA,EAC3B,CACE;AAAA,IACE,WAAAC;AAAA,IACA,SAAAC,IAAU;AAAA,IACV,YAAAC,IAAa;AAAA,IACb,eAAAC,IAAgB;AAAA,IAChB,eAAAC;AAAA,IACA,QAAAC;AAAA,IACA,QAAAC;AAAA,IACA,iBAAAC;AAAA,IACA,WAAAC,IAAY;AAAA,IACZ,WAAAC,IAAY;AAAA,IACZ,cAAAC,IAAe;AAAA,IACf,gBAAAC,IAAiBhB;AAAA,IACjB,GAAGiB;AAAA,EAAA,GAELC,MACG;AACH,UAAMC,IAAUb,MAAY,SACtBc,IAASd,MAAY;AAE3B,WACE,gBAAAe;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAAH;AAAA,QACA,WAAWI;AAAA,UACT;AAAA,UACAjB;AAAA,QAAA;AAAA,QAED,GAAGY;AAAA,QAEJ,UAAA;AAAA,UAAA,gBAAAM;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWD;AAAA,gBACT;AAAA,gBACAH,KAAW;AAAA,cAAA;AAAA,cAGZ,UAAA,CAACA,KACA,gBAAAI,EAACC,GAAA,EAAO,SAAQ,aAAY,SAASd,GAClC,UAAAG,EAAA,CACH;AAAA,YAAA;AAAA,UAAA;AAAA,UAIJ,gBAAAU;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cAET,UAAA,MAAM,KAAK,EAAE,QAAQhB,KAAc,CAACkB,GAAGxB,MAAU;AAChD,sBAAMyB,IAAWzB,MAAUO;AAC3B,uBACE,gBAAAe;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBAEC,MAAK;AAAA,oBACL,gBAAcG,KAAY;AAAA,oBAC1B,cAAYV,EAAef,GAAOM,CAAU;AAAA,oBAC5C,SAAS,MAAME,KAAA,gBAAAA,EAAgBR;AAAA,oBAC/B,WAAU;AAAA,oBAEV,UAAA,gBAAAsB;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,WAAWD;AAAA,0BACT;AAAA,0BACAI,IACI,4CACA;AAAA,wBAAA;AAAA,sBACN;AAAA,oBAAA;AAAA,kBACF;AAAA,kBAdKzB;AAAA,gBAAA;AAAA,cAiBX,CAAC;AAAA,YAAA;AAAA,UAAA;AAAA,UAGH,gBAAAsB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cAEV,UAAA,gBAAAA,EAACC,KAAO,SAASJ,IAASR,IAAkBD,GACzC,UAAAS,IAASL,IAAeD,EAAA,CAC3B;AAAA,YAAA;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACF;AACAX,EAAe,cAAc;"}
@@ -0,0 +1,126 @@
1
+ import { jsxs as r, jsx as l, Fragment as z } from "react/jsx-runtime";
2
+ import * as b from "react";
3
+ import { cva as I } from "../../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js";
4
+ import { cn as x } from "../../../lib/utils.js";
5
+ import { ChartStyle as y } from "../chart/chart.js";
6
+ import { Tooltip as B, TooltipTrigger as O, TooltipContent as S } from "../tooltip/tooltip.js";
7
+ const q = (c) => c.toLocaleString(), F = I("flex w-full overflow-hidden rounded-full bg-input", {
8
+ variants: {
9
+ size: {
10
+ sm: "h-1.5",
11
+ md: "h-2.5",
12
+ lg: "h-4"
13
+ }
14
+ },
15
+ defaultVariants: {
16
+ size: "md"
17
+ }
18
+ }), R = b.forwardRef(
19
+ ({
20
+ className: c,
21
+ data: n,
22
+ config: o,
23
+ size: g,
24
+ showLegend: k = !1,
25
+ showTooltip: v = !0,
26
+ tooltipContent: d,
27
+ valueFormatter: i = q,
28
+ defaultOpenIndex: N,
29
+ "aria-label": w,
30
+ ...C
31
+ }, T) => {
32
+ const s = `chart-${b.useId().replace(/:/g, "")}`, f = n.reduce((e, a) => e + a.value, 0), u = (e) => {
33
+ var a;
34
+ return ((a = o[e]) == null ? void 0 : a.label) ?? e;
35
+ }, $ = (e) => {
36
+ var t;
37
+ const a = (t = o[e]) == null ? void 0 : t.label;
38
+ return typeof a == "string" || typeof a == "number" ? String(a) : e;
39
+ }, p = (e) => `var(--color-${e})`, m = (e) => f > 0 ? Math.round(e / f * 100) : 0, j = w ?? n.map((e) => `${$(e.key)} ${i(e.value)}`).join(", ");
40
+ return /* @__PURE__ */ r(
41
+ "div",
42
+ {
43
+ ref: T,
44
+ "data-chart": s,
45
+ className: x("flex w-full flex-col gap-3", c),
46
+ ...C,
47
+ children: [
48
+ /* @__PURE__ */ l(y, { id: s, config: o }),
49
+ /* @__PURE__ */ l("div", { className: F({ size: g }), role: "img", "aria-label": j, children: n.map((e, a) => {
50
+ const t = p(e.key), h = /* @__PURE__ */ l(
51
+ "div",
52
+ {
53
+ className: "h-full min-w-0",
54
+ style: { flex: `${e.value} 0 0%`, backgroundColor: t }
55
+ },
56
+ e.key
57
+ );
58
+ return v ? /* @__PURE__ */ r(B, { defaultOpen: a === N, children: [
59
+ /* @__PURE__ */ l(O, { render: h }),
60
+ /* @__PURE__ */ r(
61
+ S,
62
+ {
63
+ "data-chart": s,
64
+ className: x(
65
+ "border border-border bg-background text-foreground shadow-md",
66
+ !d && "flex items-center gap-2"
67
+ ),
68
+ children: [
69
+ /* @__PURE__ */ l(y, { id: s, config: o }),
70
+ d ? d({
71
+ key: e.key,
72
+ value: e.value,
73
+ label: u(e.key),
74
+ percent: m(e.value),
75
+ color: t
76
+ }) : /* @__PURE__ */ r(z, { children: [
77
+ /* @__PURE__ */ l(
78
+ "span",
79
+ {
80
+ className: "size-2.5 shrink-0 rounded-full",
81
+ style: { backgroundColor: t }
82
+ }
83
+ ),
84
+ /* @__PURE__ */ l("span", { className: "font-semibold", children: u(e.key) }),
85
+ /* @__PURE__ */ r("span", { className: "text-muted-foreground tabular-nums", children: [
86
+ i(e.value),
87
+ " · ",
88
+ m(e.value),
89
+ "%"
90
+ ] })
91
+ ] })
92
+ ]
93
+ }
94
+ )
95
+ ] }, e.key) : h;
96
+ }) }),
97
+ k && /* @__PURE__ */ l("ul", { className: "flex flex-wrap justify-between gap-x-6 gap-y-3", children: n.map((e) => /* @__PURE__ */ r("li", { className: "flex flex-col gap-1.5", children: [
98
+ /* @__PURE__ */ r("span", { className: "flex items-center gap-1.5 text-sm leading-none text-muted-foreground", children: [
99
+ /* @__PURE__ */ l(
100
+ "span",
101
+ {
102
+ className: "size-2.5 shrink-0 rounded-full",
103
+ style: { backgroundColor: p(e.key) }
104
+ }
105
+ ),
106
+ u(e.key)
107
+ ] }),
108
+ /* @__PURE__ */ r("span", { className: "flex items-baseline gap-1.5 leading-none tabular-nums", children: [
109
+ /* @__PURE__ */ l("span", { className: "text-base font-semibold text-foreground", children: i(e.value) }),
110
+ /* @__PURE__ */ r("span", { className: "text-sm text-muted-foreground", children: [
111
+ m(e.value),
112
+ "%"
113
+ ] })
114
+ ] })
115
+ ] }, e.key)) })
116
+ ]
117
+ }
118
+ );
119
+ }
120
+ );
121
+ R.displayName = "CategoryBar";
122
+ export {
123
+ R as CategoryBar,
124
+ F as categoryBarVariants
125
+ };
126
+ //# sourceMappingURL=category-bar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"category-bar.js","sources":["../../../../src/components/ui/category-bar/category-bar.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nimport { cn } from '@/lib/utils';\nimport { ChartStyle, type ChartConfig } from '../chart';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip';\n\n// A category bar: a single horizontal bar split into proportional colored\n// segments — one part-to-whole across a handful of categories, in one row\n// (onboarding stages, certification status, a rating scale). Unlike `Meter`\n// (one value per row, stacked into a bar list), all segments share the same bar.\n// It's a plain flex composition, not a recharts chart: each segment's width is\n// `value / total`, so exact proportions and the count/% legend are direct DOM,\n// with no axes/grid to hide. Segment colors are caller-supplied via `config`\n// (existing semantic `--ui-*` tokens); there is no chart palette tier yet.\n//\n// Colors are consumed through the same `--color-<key>` bridge the recharts\n// charts use: `ChartStyle` emits one custom property per config entry, so a\n// `theme: { light, dark }` entry works as well as a flat `color` — reading\n// `config[key].color` directly would render a themed config colorless. The\n// tooltip is portaled out of the bar's DOM, so its popup carries its own\n// `data-chart` scope + `ChartStyle` to keep the bridge resolvable there.\n\nconst defaultFormat = (value: number) => value.toLocaleString();\n\n// Track height only — the flex/rounded/overflow chrome is static.\nconst categoryBarVariants = cva('flex w-full overflow-hidden rounded-full bg-input', {\n variants: {\n size: {\n sm: 'h-1.5',\n md: 'h-2.5',\n lg: 'h-4',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\nexport interface CategoryBarSegment {\n /** Key into `config` for this segment's label + color. */\n key: string;\n /** The segment's value — its width is this over the sum of all values. */\n value: number;\n}\n\n/** The resolved segment passed to a custom `tooltipContent` renderer. */\nexport interface CategoryBarTooltipContext extends CategoryBarSegment {\n /** Resolved `config` label (falls back to the key); may be any `ReactNode`. */\n label: React.ReactNode;\n /** Share of the total as a rounded percentage (0–100). */\n percent: number;\n /**\n * CSS color reference for the segment — the `var(--color-<key>)` bridge, which\n * resolves the config entry's `color` or its per-theme `theme` value. Usable\n * anywhere a CSS color is (e.g. a `style` background); not a literal value.\n */\n color: string;\n}\n\nexport interface CategoryBarProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n VariantProps<typeof categoryBarVariants> {\n /** Ordered segments (left → right). Widths are proportional to `value`. */\n data: ReadonlyArray<CategoryBarSegment>;\n /** Maps each segment `key` to a `label` and `color` (an existing `--ui-*` token). */\n config: ChartConfig;\n /** Show the legend below the bar (color dot + label + value + %). */\n showLegend?: boolean;\n /** Show a hover tooltip per segment (dot + label + value + %). */\n showTooltip?: boolean;\n /**\n * Custom tooltip content per segment — replaces the default (dot + label +\n * `value · %`) inside the same card. Ignored when `showTooltip` is false.\n */\n tooltipContent?: (segment: CategoryBarTooltipContext) => React.ReactNode;\n /** Format the numeric value (legend + tooltip). Defaults to `toLocaleString()`. */\n valueFormatter?: (value: number) => string;\n /** Render the tooltip for this segment index initially open (VR/testing). */\n defaultOpenIndex?: number;\n /**\n * Accessible summary of the whole bar. Defaults to a `label value` list built\n * from the data; pass a fuller sentence for screen readers if you have one.\n */\n 'aria-label'?: string;\n}\n\nconst CategoryBar = React.forwardRef<HTMLDivElement, CategoryBarProps>(\n (\n {\n className,\n data,\n config,\n size,\n showLegend = false,\n showTooltip = true,\n tooltipContent,\n valueFormatter = defaultFormat,\n defaultOpenIndex,\n 'aria-label': ariaLabel,\n ...props\n },\n ref\n ) => {\n const uniqueId = React.useId();\n const chartId = `chart-${uniqueId.replace(/:/g, '')}`;\n\n const total = data.reduce((sum, seg) => sum + seg.value, 0);\n const labelFor = (key: string): React.ReactNode => config[key]?.label ?? key;\n // The aria-label has to be a plain string, so a rich (element) label can't\n // be used there — fall back to the key rather than stringifying it into\n // \"[object Object]\".\n const labelTextFor = (key: string) => {\n const label = config[key]?.label;\n return typeof label === 'string' || typeof label === 'number'\n ? String(label)\n : key;\n };\n const colorOf = (key: string) => `var(--color-${key})`;\n const pctOf = (value: number) =>\n total > 0 ? Math.round((value / total) * 100) : 0;\n\n // A locale-neutral fallback: \"<label> <value>\" pairs. Consumers can pass a\n // fuller `aria-label` sentence.\n const summary =\n ariaLabel ??\n data\n .map((seg) => `${labelTextFor(seg.key)} ${valueFormatter(seg.value)}`)\n .join(', ');\n\n return (\n <div\n ref={ref}\n data-chart={chartId}\n className={cn('flex w-full flex-col gap-3', className)}\n {...props}\n >\n <ChartStyle id={chartId} config={config} />\n <div className={categoryBarVariants({ size })} role=\"img\" aria-label={summary}>\n {data.map((seg, index) => {\n const color = colorOf(seg.key);\n // flex-grow proportional to value with a zero basis → widths are\n // exactly value/total; a zero-value segment collapses.\n const segment = (\n <div\n key={seg.key}\n className=\"h-full min-w-0\"\n style={{ flex: `${seg.value} 0 0%`, backgroundColor: color }}\n />\n );\n\n if (!showTooltip) return segment;\n\n return (\n <Tooltip key={seg.key} defaultOpen={index === defaultOpenIndex}>\n <TooltipTrigger render={segment} />\n <TooltipContent\n // The popup is portaled out of the bar, so it needs its own\n // `data-chart` scope for the `--color-*` bridge to resolve.\n data-chart={chartId}\n className={cn(\n 'border border-border bg-background text-foreground shadow-md',\n !tooltipContent && 'flex items-center gap-2'\n )}\n >\n <ChartStyle id={chartId} config={config} />\n {tooltipContent ? (\n tooltipContent({\n key: seg.key,\n value: seg.value,\n label: labelFor(seg.key),\n percent: pctOf(seg.value),\n color,\n })\n ) : (\n <>\n <span\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: color }}\n />\n <span className=\"font-semibold\">{labelFor(seg.key)}</span>\n <span className=\"text-muted-foreground tabular-nums\">\n {valueFormatter(seg.value)} · {pctOf(seg.value)}%\n </span>\n </>\n )}\n </TooltipContent>\n </Tooltip>\n );\n })}\n </div>\n\n {showLegend && (\n <ul className=\"flex flex-wrap justify-between gap-x-6 gap-y-3\">\n {data.map((seg) => (\n <li key={seg.key} className=\"flex flex-col gap-1.5\">\n <span className=\"flex items-center gap-1.5 text-sm leading-none text-muted-foreground\">\n <span\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: colorOf(seg.key) }}\n />\n {labelFor(seg.key)}\n </span>\n <span className=\"flex items-baseline gap-1.5 leading-none tabular-nums\">\n <span className=\"text-base font-semibold text-foreground\">\n {valueFormatter(seg.value)}\n </span>\n <span className=\"text-sm text-muted-foreground\">\n {pctOf(seg.value)}%\n </span>\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n }\n);\nCategoryBar.displayName = 'CategoryBar';\n\nexport { CategoryBar, categoryBarVariants };\n"],"names":["defaultFormat","value","categoryBarVariants","cva","CategoryBar","React","className","data","config","size","showLegend","showTooltip","tooltipContent","valueFormatter","defaultOpenIndex","ariaLabel","props","ref","chartId","total","sum","seg","labelFor","key","_a","labelTextFor","label","colorOf","pctOf","summary","jsxs","cn","jsx","ChartStyle","index","color","segment","Tooltip","TooltipTrigger","TooltipContent","Fragment"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ function i(t) {
2
+ switch (t) {
3
+ case "auto":
4
+ return ["auto", "auto"];
5
+ case "zero":
6
+ return [0, "auto"];
7
+ case "dataMin-dataMax":
8
+ return ["dataMin", "dataMax"];
9
+ default:
10
+ return;
11
+ }
12
+ }
13
+ const r = (t) => {
14
+ if (typeof t == "string" && t.trim() === "") return null;
15
+ const n = typeof t == "number" ? t : Number(t);
16
+ return Number.isFinite(n) ? n : null;
17
+ }, u = (t) => {
18
+ const n = r(t);
19
+ return n === null ? String(t) : new Intl.NumberFormat("en", {
20
+ notation: "compact",
21
+ maximumFractionDigits: 1
22
+ }).format(n);
23
+ }, c = (t) => {
24
+ const n = r(t);
25
+ return n === null ? String(t) : `${n}%`;
26
+ };
27
+ function m(t, n = "en") {
28
+ const a = new Intl.NumberFormat(n, t);
29
+ return (o) => {
30
+ const e = r(o);
31
+ return e === null ? String(o) : a.format(e);
32
+ };
33
+ }
34
+ export {
35
+ m as createTickFormatter,
36
+ u as formatCompactNumber,
37
+ c as formatPercent,
38
+ i as resolveAxisDomain
39
+ };
40
+ //# sourceMappingURL=chart-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-format.js","sources":["../../../../src/components/ui/chart/chart-format.ts"],"sourcesContent":["// Shared axis helpers for the cartesian chart components (BarChart, LineChart,\n// AreaChart, ComposedChart, ScatterChart, ConfidenceCone, Histogram). Three\n// concerns live here so every chart formats + toggles axes the same way rather\n// than each reimplementing it:\n//\n// 1. `CartesianChartProps` — the common axis knobs each cartesian chart mixes\n// into its own props (show/hide either axis, per-axis tick formatting).\n// 2. A small set of tick formatters (+ a factory) callers pass to\n// `xTickFormatter` / `yTickFormatter`.\n// 3. `resolveAxisDomain` — maps the `yAxisDomain` preset to a recharts\n// `domain`, shared so all 7 charts can't drift apart on it.\n//\n// These format only the axis *tick labels*; series colors and tokens are\n// unaffected. Formatters coerce to a number and pass non-numeric values through\n// untouched (a category axis stays readable if a formatter is applied to it).\n\nimport type { AxisDomainItem } from 'recharts';\n\nimport type { ChartTooltipContentType } from './chart';\n\n/** A recharts-compatible tick formatter: `(value, index) => label`. */\nexport type TickFormatter = (value: number | string, index?: number) => string;\n\n/**\n * Props shared by every cartesian chart (Bar, Line, Area, Composed, Scatter,\n * ConfidenceCone, Histogram) — chrome toggles, axis titles/units, tick\n * formatting/visibility, and grid trim. All optional. `showLegend` and `xUnit`\n * are deliberately *not* here: `showLegend` doesn't apply to `Histogram` and\n * `xUnit` only to charts with a numeric X axis, so they stay per-component.\n */\nexport interface CartesianChartProps {\n /** Render the CartesianGrid. Defaults to `true`. */\n showGrid?: boolean;\n /** Render the hover tooltip. Defaults to `true`. */\n showTooltip?: boolean;\n /**\n * Replace the default tooltip. Pass a configured `ChartTooltipContent` (from\n * this library) — e.g. with a `formatter` / `labelFormatter` — to customize it\n * without composing recharts yourself. Ignored when `showTooltip` is false.\n */\n tooltipContent?: ChartTooltipContentType;\n /** Title rendered beneath the X axis. */\n xAxisLabel?: string;\n /** Title rendered beside the Y axis (rotated). */\n yAxisLabel?: string;\n /**\n * Unit suffix appended to the Y axis's tick values (recharts `unit`) — applies\n * when the Y axis is the numeric one. `BarChart` with\n * `orientation=\"horizontal\"` puts the values on X instead; use `xUnit` there.\n */\n yUnit?: string;\n /** Show the X axis (its ticks + title). Defaults to `true`. */\n showXAxis?: boolean;\n /** Show the Y axis (its ticks + title). Defaults to `true`. */\n showYAxis?: boolean;\n /** Format each X-axis tick value — e.g. `formatCompactNumber` or a `createTickFormatter(...)`. */\n xTickFormatter?: TickFormatter;\n /** Format each Y-axis tick value — e.g. `formatCompactNumber` or a `createTickFormatter(...)`. */\n yTickFormatter?: TickFormatter;\n /**\n * Rotate the X-axis tick labels by this many degrees. A negative angle (e.g.\n * `-45`) tilts them up toward the right; the tick anchor + axis height adjust\n * to keep long labels readable.\n */\n xAxisAngle?: number;\n /**\n * X-axis tick density — a recharts placement strategy, or a fixed number of\n * ticks to *skip* between two rendered ones (recharts `interval`: `0` shows\n * every tick, `1` every other one, `2` every third, …).\n */\n xAxisInterval?:\n | number\n | 'preserveStart'\n | 'preserveEnd'\n | 'preserveStartEnd'\n | 'equidistantPreserveStart';\n /**\n * Desired number of ticks on the value axis (recharts `tickCount`; a hint, not\n * exact). Applies to whichever axis holds the values — Y for most charts, X for\n * `BarChart` with `orientation=\"horizontal\"`.\n */\n yAxisTickCount?: number;\n /**\n * Value-axis domain preset. Applies to whichever axis holds the values — Y for\n * most charts, X for `BarChart` with `orientation=\"horizontal\"`.\n *\n * - `auto` — fit the data at both ends; the axis need not include 0.\n * - `zero` — anchor the axis at 0. This is also recharts' behavior when the\n * prop is omitted, so it's the explicit form of the default.\n * - `dataMin-dataMax` — tight to the data, with no padding.\n */\n yAxisDomain?: 'auto' | 'dataMin-dataMax' | 'zero';\n /** Draw grid lines dashed instead of solid. */\n gridDashed?: boolean;\n /** Show horizontal grid lines. Defaults to each chart's own default when unset. */\n gridHorizontal?: boolean;\n /** Show vertical grid lines. Defaults to each chart's own default when unset. */\n gridVertical?: boolean;\n}\n\n/**\n * Map a `yAxisDomain` preset to a recharts `domain`. Shared by all 7 cartesian\n * charts, and applied to whichever axis holds the values (X for horizontal bars).\n *\n * `undefined` (no preset) is left to recharts, whose default is `[0, 'auto']` —\n * i.e. already zero-anchored. That's why `auto` has to be spelled out as\n * `['auto', 'auto']`: passing `undefined` for it would silently anchor at 0 and\n * make the preset indistinguishable from `zero`.\n */\nexport function resolveAxisDomain(\n preset: 'auto' | 'dataMin-dataMax' | 'zero' | undefined\n): Readonly<[AxisDomainItem, AxisDomainItem]> | undefined {\n switch (preset) {\n case 'auto':\n return ['auto', 'auto'];\n case 'zero':\n return [0, 'auto'];\n case 'dataMin-dataMax':\n return ['dataMin', 'dataMax'];\n default:\n return undefined;\n }\n}\n\nconst toNumber = (value: number | string): number | null => {\n // `Number('')` and `Number(' ')` are 0, not NaN — so blank strings have to be\n // rejected before the finite check, or an empty tick label would render \"0\".\n if (typeof value === 'string' && value.trim() === '') return null;\n const n = typeof value === 'number' ? value : Number(value);\n return Number.isFinite(n) ? n : null;\n};\n\n/**\n * Compact thousands/millions: `1234 → \"1.2K\"`, `1_500_000 → \"1.5M\"`. Non-numeric\n * values (including blank strings) pass through unchanged. Use for large-count\n * axes (revenue, users, …).\n *\n * Formats in `en`. For another locale use\n * `createTickFormatter({ notation: 'compact', maximumFractionDigits: 1 }, locale)`.\n */\nexport const formatCompactNumber: TickFormatter = (value) => {\n const n = toNumber(value);\n if (n === null) return String(value);\n return new Intl.NumberFormat('en', {\n notation: 'compact',\n maximumFractionDigits: 1,\n }).format(n);\n};\n\n/**\n * Append a percent sign to an already-scaled value: `41.8 → \"41.8%\"`. (The value\n * is treated as a percentage, not a 0–1 fraction.) Non-numeric values (including\n * blank strings) pass through.\n *\n * Appends a bare `%`, which is not how every locale writes it. For locale-correct\n * output on values that really are fractions, use\n * `createTickFormatter({ style: 'percent' }, locale)`.\n */\nexport const formatPercent: TickFormatter = (value) => {\n const n = toNumber(value);\n if (n === null) return String(value);\n return `${n}%`;\n};\n\n/**\n * Build a tick formatter from `Intl.NumberFormat` options — the escape hatch for\n * currency, fixed decimals, or a specific locale. E.g.\n * `createTickFormatter({ style: 'currency', currency: 'USD', notation: 'compact' })`\n * → `146500 → \"$147K\"`. Non-numeric values pass through unchanged.\n */\nexport function createTickFormatter(\n options: Intl.NumberFormatOptions,\n locale = 'en'\n): TickFormatter {\n const nf = new Intl.NumberFormat(locale, options);\n return (value) => {\n const n = toNumber(value);\n return n === null ? String(value) : nf.format(n);\n };\n}\n"],"names":["resolveAxisDomain","preset","toNumber","value","formatCompactNumber","formatPercent","createTickFormatter","options","locale","nf","n"],"mappings":"AA6GO,SAASA,EACdC,GACwD;AACxD,UAAQA,GAAA;AAAA,IACN,KAAK;AACH,aAAO,CAAC,QAAQ,MAAM;AAAA,IACxB,KAAK;AACH,aAAO,CAAC,GAAG,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,CAAC,WAAW,SAAS;AAAA,IAC9B;AACE;AAAA,EAAO;AAEb;AAEA,MAAMC,IAAW,CAACC,MAA0C;AAG1D,MAAI,OAAOA,KAAU,YAAYA,EAAM,KAAA,MAAW,GAAI,QAAO;AAC7D,QAAM,IAAI,OAAOA,KAAU,WAAWA,IAAQ,OAAOA,CAAK;AAC1D,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC,GAUaC,IAAqC,CAACD,MAAU;AAC3D,QAAM,IAAID,EAASC,CAAK;AACxB,SAAI,MAAM,OAAa,OAAOA,CAAK,IAC5B,IAAI,KAAK,aAAa,MAAM;AAAA,IACjC,UAAU;AAAA,IACV,uBAAuB;AAAA,EAAA,CACxB,EAAE,OAAO,CAAC;AACb,GAWaE,IAA+B,CAACF,MAAU;AACrD,QAAM,IAAID,EAASC,CAAK;AACxB,SAAI,MAAM,OAAa,OAAOA,CAAK,IAC5B,GAAG,CAAC;AACb;AAQO,SAASG,EACdC,GACAC,IAAS,MACM;AACf,QAAMC,IAAK,IAAI,KAAK,aAAaD,GAAQD,CAAO;AAChD,SAAO,CAACJ,MAAU;AAChB,UAAMO,IAAIR,EAASC,CAAK;AACxB,WAAOO,MAAM,OAAO,OAAOP,CAAK,IAAIM,EAAG,OAAOC,CAAC;AAAA,EACjD;AACF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"chart.js","sources":["../../../../src/components/ui/chart/chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport * as RechartsPrimitive from 'recharts';\nimport type { LegendPayload } from 'recharts/types/component/DefaultLegendContent';\nimport {\n NameType,\n Payload,\n ValueType,\n} from 'recharts/types/component/DefaultTooltipContent';\nimport type { Props as LegendProps } from 'recharts/types/component/Legend';\nimport { TooltipContentProps } from 'recharts/types/component/Tooltip';\n\nimport { cn } from '@/lib/utils';\n\n// Format: { THEME_NAME: CSS_SELECTOR }. ui-react flips light/dark via the\n// `[data-theme]` attribute (the tokens resolve `light-dark()` through\n// `color-scheme`), not the legacy `.dark` class — so per-series `theme` colors\n// scope their dark value under `[data-theme='dark']`.\nconst THEMES = { light: '', dark: \"[data-theme='dark']\" } as const;\n\nexport type ChartConfig = {\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: ChartConfig;\n};\n\nexport type ChartTooltipContentProps = Partial<\n TooltipContentProps<ValueType, NameType>\n> & {\n className?: string;\n hideLabel?: boolean;\n hideIndicator?: boolean;\n indicator?: 'line' | 'dot' | 'dashed';\n nameKey?: string;\n labelKey?: string;\n labelFormatter?: (\n label: TooltipContentProps<number, string>['label'],\n payload: TooltipContentProps<number, string>['payload']\n ) => React.ReactNode;\n formatter?: (\n value: number | string,\n name: string,\n item: Payload<number | string, string>,\n index: number,\n payload: ReadonlyArray<Payload<number | string, string>>\n ) => React.ReactNode;\n labelClassName?: string;\n color?: string;\n};\n\nexport type ChartLegendContentProps = {\n className?: string;\n hideIcon?: boolean;\n verticalAlign?: LegendProps['verticalAlign'];\n payload?: LegendPayload[];\n nameKey?: string;\n};\n\nconst ChartContext = React.createContext<ChartContextProps | null>(null);\n\nfunction useChart() {\n const context = React.useContext(ChartContext);\n\n if (!context) {\n throw new Error('useChart must be used within a <ChartContainer />');\n }\n\n return context;\n}\n\nexport interface ChartContainerProps extends React.ComponentProps<'div'> {\n config: ChartConfig;\n children: React.ComponentProps<\n typeof RechartsPrimitive.ResponsiveContainer\n >['children'];\n}\n\nfunction ChartContainer({\n id,\n className,\n children,\n config,\n ...props\n}: ChartContainerProps) {\n const uniqueId = React.useId();\n const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`;\n\n return (\n <ChartContext.Provider value={{ config }}>\n <div\n id={id}\n data-slot=\"chart\"\n data-chart={chartId}\n className={cn(\n \"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden\",\n className\n )}\n {...props}\n >\n <ChartStyle id={chartId} config={config} />\n <RechartsPrimitive.ResponsiveContainer>\n {children}\n </RechartsPrimitive.ResponsiveContainer>\n </div>\n </ChartContext.Provider>\n );\n}\n\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\n const colorConfig = Object.entries(config).filter(\n ([, config]) => config.theme || config.color\n );\n\n if (!colorConfig.length) {\n return null;\n }\n\n // Rendered as a text child (not dangerouslySetInnerHTML): React sets it via\n // textContent, which the browser does not HTML-parse, so a `</style>` in a\n // config color can't break out of the tag.\n return (\n <style>\n {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 </style>\n );\n};\n\nconst ChartTooltip = RechartsPrimitive.Tooltip;\n\nfunction ChartTooltipContent({\n active,\n payload,\n label,\n className,\n indicator = 'dot',\n hideLabel = false,\n hideIndicator = false,\n labelFormatter,\n formatter,\n labelClassName,\n color,\n nameKey,\n labelKey,\n}: ChartTooltipContentProps) {\n const { config } = useChart();\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 value = (() => {\n const v =\n !labelKey && typeof label === 'string'\n ? (config[label as keyof typeof config]?.label ?? label)\n : itemConfig?.label;\n\n return typeof v === 'string' || typeof v === 'number' ? v : undefined;\n })();\n\n if (labelFormatter) {\n return (\n <div className={cn('font-medium', 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', 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 className={cn(\n 'grid min-w-[8rem] items-start gap-1.5 rounded-[var(--ui-tooltip-container-border-radius)] border border-border bg-background px-[var(--ui-tooltip-container-padding-x)] py-[var(--ui-tooltip-container-padding-y)] text-xs text-foreground shadow-md',\n className\n )}\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={key}\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, payload)\n ) : (\n <>\n {itemConfig?.icon ? (\n <itemConfig.icon />\n ) : (\n !hideIndicator && (\n <div\n className={cn(\n 'shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)',\n {\n 'h-2.5 w-2.5': indicator === 'dot',\n 'h-4 w-1': indicator === 'line',\n 'h-4 w-0 border-[1.5px] border-dashed bg-transparent':\n indicator === 'dashed',\n 'my-0.5': nestLabel && indicator === 'dashed',\n }\n )}\n style={\n {\n '--color-bg': indicatorColor,\n '--color-border': indicatorColor,\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-muted-foreground\">\n {itemConfig?.label || item.name}\n </span>\n </div>\n {item.value != null && (\n <span className=\"font-medium tabular-nums text-foreground\">\n {item.value.toLocaleString()}\n </span>\n )}\n </div>\n </>\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nconst ChartLegend = RechartsPrimitive.Legend;\n\nfunction ChartLegendContent({\n className,\n hideIcon = false,\n payload,\n verticalAlign = 'bottom',\n nameKey,\n}: ChartLegendContentProps) {\n const { config } = useChart();\n\n if (!payload?.length) {\n return null;\n }\n\n return (\n <div\n className={cn(\n 'flex items-center justify-center gap-4',\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 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground'\n )}\n >\n {itemConfig?.icon && !hideIcon ? (\n <itemConfig.icon />\n ) : (\n <div\n className=\"h-2 w-2 shrink-0 rounded-[2px]\"\n style={{\n backgroundColor: item.color,\n }}\n />\n )}\n {itemConfig?.label}\n </div>\n );\n })}\n </div>\n );\n}\n\n// Helper to extract item config from a payload.\nfunction getPayloadConfigFromPayload(\n config: ChartConfig,\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\nexport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n ChartLegend,\n ChartLegendContent,\n ChartStyle,\n};\n"],"names":["THEMES","ChartContext","React","useChart","context","ChartContainer","id","className","children","config","props","uniqueId","chartId","jsxs","cn","jsx","ChartStyle","RechartsPrimitive","colorConfig","theme","prefix","key","itemConfig","color","_a","ChartTooltip","ChartTooltipContent","active","payload","label","indicator","hideLabel","hideIndicator","labelFormatter","formatter","labelClassName","nameKey","labelKey","tooltipLabel","item","getPayloadConfigFromPayload","value","v","nestLabel","index","indicatorColor","Fragment","ChartLegend","ChartLegendContent","hideIcon","verticalAlign","payloadPayload","configLabelKey"],"mappings":"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"}
1
+ {"version":3,"file":"chart.js","sources":["../../../../src/components/ui/chart/chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport * as RechartsPrimitive from 'recharts';\nimport type { LegendPayload } from 'recharts/types/component/DefaultLegendContent';\nimport {\n NameType,\n Payload,\n ValueType,\n} from 'recharts/types/component/DefaultTooltipContent';\nimport type { Props as LegendProps } from 'recharts/types/component/Legend';\nimport { TooltipContentProps } from 'recharts/types/component/Tooltip';\n\nimport { cn } from '@/lib/utils';\n\n// Format: { THEME_NAME: CSS_SELECTOR }. ui-react flips light/dark via the\n// `[data-theme]` attribute (the tokens resolve `light-dark()` through\n// `color-scheme`), not the legacy `.dark` class — so per-series `theme` colors\n// scope their dark value under `[data-theme='dark']`.\nconst THEMES = { light: '', dark: \"[data-theme='dark']\" } as const;\n\nexport type ChartConfig = {\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: ChartConfig;\n};\n\nexport type ChartTooltipContentProps = Partial<\n TooltipContentProps<ValueType, NameType>\n> & {\n className?: string;\n hideLabel?: boolean;\n hideIndicator?: boolean;\n indicator?: 'line' | 'dot' | 'dashed';\n nameKey?: string;\n labelKey?: string;\n labelFormatter?: (\n label: TooltipContentProps<number, string>['label'],\n payload: TooltipContentProps<number, string>['payload']\n ) => React.ReactNode;\n formatter?: (\n value: number | string,\n name: string,\n item: Payload<number | string, string>,\n index: number,\n payload: ReadonlyArray<Payload<number | string, string>>\n ) => React.ReactNode;\n labelClassName?: string;\n color?: string;\n};\n\nexport type ChartLegendContentProps = {\n className?: string;\n hideIcon?: boolean;\n verticalAlign?: LegendProps['verticalAlign'];\n payload?: LegendPayload[];\n nameKey?: string;\n};\n\nconst ChartContext = React.createContext<ChartContextProps | null>(null);\n\nfunction useChart() {\n const context = React.useContext(ChartContext);\n\n if (!context) {\n throw new Error('useChart must be used within a <ChartContainer />');\n }\n\n return context;\n}\n\nexport interface ChartContainerProps extends React.ComponentProps<'div'> {\n config: ChartConfig;\n children: React.ComponentProps<\n typeof RechartsPrimitive.ResponsiveContainer\n >['children'];\n}\n\nfunction ChartContainer({\n id,\n className,\n children,\n config,\n ...props\n}: ChartContainerProps) {\n const uniqueId = React.useId();\n const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`;\n\n return (\n <ChartContext.Provider value={{ config }}>\n <div\n id={id}\n data-slot=\"chart\"\n data-chart={chartId}\n className={cn(\n \"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden\",\n className\n )}\n {...props}\n >\n <ChartStyle id={chartId} config={config} />\n <RechartsPrimitive.ResponsiveContainer>\n {children}\n </RechartsPrimitive.ResponsiveContainer>\n </div>\n </ChartContext.Provider>\n );\n}\n\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\n const colorConfig = Object.entries(config).filter(\n ([, config]) => config.theme || config.color\n );\n\n if (!colorConfig.length) {\n return null;\n }\n\n // Rendered as a text child (not dangerouslySetInnerHTML): React sets it via\n // textContent, which the browser does not HTML-parse, so a `</style>` in a\n // config color can't break out of the tag.\n return (\n <style>\n {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 </style>\n );\n};\n\nconst ChartTooltip = RechartsPrimitive.Tooltip;\n\n/** The `content` a caller passes to override the default tooltip (recharts' `Tooltip['content']`). */\nexport type ChartTooltipContentType = React.ComponentProps<\n typeof ChartTooltip\n>['content'];\n\nfunction ChartTooltipContent({\n active,\n payload,\n label,\n className,\n indicator = 'dot',\n hideLabel = false,\n hideIndicator = false,\n labelFormatter,\n formatter,\n labelClassName,\n color,\n nameKey,\n labelKey,\n}: ChartTooltipContentProps) {\n const { config } = useChart();\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 value = (() => {\n const v =\n !labelKey && typeof label === 'string'\n ? (config[label as keyof typeof config]?.label ?? label)\n : itemConfig?.label;\n\n return typeof v === 'string' || typeof v === 'number' ? v : undefined;\n })();\n\n if (labelFormatter) {\n return (\n <div className={cn('font-medium', 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', 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 className={cn(\n 'grid min-w-[8rem] items-start gap-1.5 rounded-[var(--ui-tooltip-container-border-radius)] border border-border bg-background px-[var(--ui-tooltip-container-padding-x)] py-[var(--ui-tooltip-container-padding-y)] text-xs text-foreground shadow-md',\n className\n )}\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={key}\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, payload)\n ) : (\n <>\n {itemConfig?.icon ? (\n <itemConfig.icon />\n ) : (\n !hideIndicator && (\n <div\n className={cn(\n 'shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)',\n {\n 'h-2.5 w-2.5': indicator === 'dot',\n 'h-4 w-1': indicator === 'line',\n 'h-4 w-0 border-[1.5px] border-dashed bg-transparent':\n indicator === 'dashed',\n 'my-0.5': nestLabel && indicator === 'dashed',\n }\n )}\n style={\n {\n '--color-bg': indicatorColor,\n '--color-border': indicatorColor,\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-muted-foreground\">\n {itemConfig?.label || item.name}\n </span>\n </div>\n {item.value != null && (\n <span className=\"font-medium tabular-nums text-foreground\">\n {item.value.toLocaleString()}\n </span>\n )}\n </div>\n </>\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nconst ChartLegend = RechartsPrimitive.Legend;\n\nfunction ChartLegendContent({\n className,\n hideIcon = false,\n payload,\n verticalAlign = 'bottom',\n nameKey,\n}: ChartLegendContentProps) {\n const { config } = useChart();\n\n if (!payload?.length) {\n return null;\n }\n\n return (\n <div\n className={cn(\n 'flex items-center justify-center gap-4',\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 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground'\n )}\n >\n {itemConfig?.icon && !hideIcon ? (\n <itemConfig.icon />\n ) : (\n <div\n className=\"h-2 w-2 shrink-0 rounded-[2px]\"\n style={{\n backgroundColor: item.color,\n }}\n />\n )}\n {itemConfig?.label}\n </div>\n );\n })}\n </div>\n );\n}\n\n// Helper to extract item config from a payload.\nfunction getPayloadConfigFromPayload(\n config: ChartConfig,\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\nexport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n ChartLegend,\n ChartLegendContent,\n ChartStyle,\n};\n"],"names":["THEMES","ChartContext","React","useChart","context","ChartContainer","id","className","children","config","props","uniqueId","chartId","jsxs","cn","jsx","ChartStyle","RechartsPrimitive","colorConfig","theme","prefix","key","itemConfig","color","_a","ChartTooltip","ChartTooltipContent","active","payload","label","indicator","hideLabel","hideIndicator","labelFormatter","formatter","labelClassName","nameKey","labelKey","tooltipLabel","item","getPayloadConfigFromPayload","value","v","nestLabel","index","indicatorColor","Fragment","ChartLegend","ChartLegendContent","hideIcon","verticalAlign","payloadPayload","configLabelKey"],"mappings":"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"}