@dreamtree-org/twreact-ui 2.0.4 → 2.0.6

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 (60) hide show
  1. package/README.md +12 -4
  2. package/ai-skills/dreamtree-ui.md +4 -3
  3. package/dist/ai-schema.json +135 -0
  4. package/dist/charts/index.d.ts +2 -1
  5. package/dist/charts/index.js +298 -13
  6. package/dist/components/charts/ChartFrame.d.ts +1 -0
  7. package/dist/components/charts/ChartFrame.d.ts.map +1 -1
  8. package/dist/components/charts/ScatterChart.d.ts +4 -0
  9. package/dist/components/charts/ScatterChart.d.ts.map +1 -0
  10. package/dist/components/charts/ScatterTooltip.d.ts +14 -0
  11. package/dist/components/charts/ScatterTooltip.d.ts.map +1 -0
  12. package/dist/components/charts/scatterData.d.ts +17 -0
  13. package/dist/components/charts/scatterData.d.ts.map +1 -0
  14. package/dist/components/core/Popover.d.ts.map +1 -1
  15. package/dist/components/feedback/Tour.d.ts.map +1 -1
  16. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  17. package/dist/components/utility/Sortable.d.ts.map +1 -1
  18. package/dist/components/utility/SortableGroup.d.ts +15 -0
  19. package/dist/components/utility/SortableGroup.d.ts.map +1 -0
  20. package/dist/esm/charts/index.js +1 -0
  21. package/dist/esm/components/charts/ChartFrame.js +6 -6
  22. package/dist/esm/components/charts/ScatterChart.js +204 -0
  23. package/dist/esm/components/charts/ScatterTooltip.js +61 -0
  24. package/dist/esm/components/charts/scatterData.js +43 -0
  25. package/dist/esm/components/core/Accordion.js +2 -2
  26. package/dist/esm/components/core/DatePicker.js +3 -3
  27. package/dist/esm/components/core/DateRangePicker.js +3 -3
  28. package/dist/esm/components/core/Form.js +3 -3
  29. package/dist/esm/components/core/LocationPicker.js +1 -1
  30. package/dist/esm/components/core/Popover.js +1 -1
  31. package/dist/esm/components/core/Select.js +16 -16
  32. package/dist/esm/components/core/Table/Table.js +1 -1
  33. package/dist/esm/components/core/internal/Calendar.js +2 -2
  34. package/dist/esm/components/feedback/Drawer.js +5 -5
  35. package/dist/esm/components/feedback/Tour.js +1 -1
  36. package/dist/esm/components/rich-text/RichTextEditor.js +2 -2
  37. package/dist/esm/components/rich-text/RichTextToolbar.js +1 -1
  38. package/dist/esm/components/utility/Pagination.js +1 -1
  39. package/dist/esm/components/utility/Sortable.js +70 -48
  40. package/dist/esm/components/utility/SortableGroup.js +48 -0
  41. package/dist/esm/hooks/useSortable.js +96 -30
  42. package/dist/esm/hooks/useSortableGroup.js +268 -0
  43. package/dist/esm/index.js +1 -0
  44. package/dist/hooks/useSortable.d.ts +12 -3
  45. package/dist/hooks/useSortable.d.ts.map +1 -1
  46. package/dist/hooks/useSortableGroup.d.ts +43 -0
  47. package/dist/hooks/useSortableGroup.d.ts.map +1 -0
  48. package/dist/index.css +1 -1
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.esm.css +1 -1
  51. package/dist/index.esm.js +904 -513
  52. package/dist/index.js +904 -512
  53. package/dist/rich-text/index.js +3 -3
  54. package/dist/types/charts.d.ts +28 -0
  55. package/dist/types/charts.d.ts.map +1 -1
  56. package/dist/types/index.d.ts +33 -0
  57. package/dist/types/index.d.ts.map +1 -1
  58. package/doc/README.md +2 -0
  59. package/mcp/catalog.snapshot.json +248 -28
  60. package/package.json +1 -1
package/README.md CHANGED
@@ -132,7 +132,7 @@ nothing changes in your bundle — the root `@dreamtree-org/twreact-ui` import n
132
132
 
133
133
  | Entry point | Exports | Install first |
134
134
  |---|---|---|
135
- | `@dreamtree-org/twreact-ui/charts` | `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, `Sparkline` | `npm install recharts` (recharts 2.15+ or 3.x; React 18 apps also `npm install react-is@18`) |
135
+ | `@dreamtree-org/twreact-ui/charts` | `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, `Sparkline`, `ScatterChart` | `npm install recharts` (recharts 2.15+ or 3.x; React 18 apps also `npm install react-is@18`) |
136
136
  | `@dreamtree-org/twreact-ui/rich-text` | `RichTextEditor` | `npm install @tiptap/react @tiptap/pm @tiptap/starter-kit` (Tiptap 3) |
137
137
 
138
138
  ```jsx
@@ -761,6 +761,7 @@ Interaction primitives that products used to compose by hand. All are `forwardRe
761
761
  | [`Textarea`](doc/Textarea.md) | Core | Multi-line input mirroring `Input`: `label`, `error`, `helperText`, `required`, `showCount`/`maxLength`, `autoResize`/`maxRows` |
762
762
  | [`Slider`](doc/Slider.md) | Core | Single value or `[low, high]` range; `min`/`max`/`step`, arrows/PageUp/PageDown/Home/End, `role="slider"` with full `aria-value*` |
763
763
  | [`Sortable`](doc/Sortable.md) | Utility | Drag-to-reorder list (pointer events, no extra dependency) + keyboard reordering (Space, arrows, Space/Escape) with live announcements; `items`, `onReorder`, `renderItem`, `getKey` |
764
+ | [`SortableGroup`](doc/SortableGroup.md) | Utility | Moves items between `Sortable` lists (each with an `id`): pointer drag or cross-axis arrow keys, `onMove({ item, from, to })`, and `canDrop(item, target, from)` which marks and announces a refused list before the drop |
764
765
  | [`Tour`](doc/Tour.md) | Feedback | Step-based onboarding: spotlight on each `target` (selector or ref), Back/Next/Skip/Finish, `open`/`onClose`/`onFinish`, scrolls targets into view |
765
766
  | [`ActionSheet`](doc/ActionSheet.md) | Feedback | iOS action sheet on `Sheet`: `actions=[{ key?, label, icon?, tone?: 'default' | 'destructive', disabled?, onSelect }]`, optional `title`/`message`, a separate Cancel button, `onClose(reason)` |
766
767
  | [`SegmentedControl`](doc/SegmentedControl.md) | Core | Radiogroup view toggle (list/board, day/week): `options`, `value`/`defaultValue` + `onChange`, `size`, `fullWidth`, `name` for forms; arrow keys move the selection. Use `Tabs variant="segmented"` when the choice switches panels |
@@ -770,7 +771,7 @@ Interaction primitives that products used to compose by hand. All are `forwardRe
770
771
  | [`BottomActionBar`](doc/BottomActionBar.md) | Block | Sticky bottom bar for a form's primary action: `pb-safe`, rides above the on-screen keyboard (`keyboardAware`), `stackOnMobile`; add `<BottomActionBar.Spacer />` at the end of the page |
771
772
 
772
773
  ```jsx
773
- import { Drawer, Sheet, Popover, Textarea, Slider, Sortable, Tour, Button } from '@dreamtree-org/twreact-ui';
774
+ import { Drawer, Sheet, Popover, Textarea, Slider, Sortable, SortableGroup, Tour, Button } from '@dreamtree-org/twreact-ui';
774
775
 
775
776
  <Drawer isOpen={open} onClose={() => setOpen(false)} title="Edit task" footer={<Button onClick={save}>Save</Button>}>
776
777
  <Textarea label="Description" autoResize showCount maxLength={500} />
@@ -787,6 +788,11 @@ import { Drawer, Sheet, Popover, Textarea, Slider, Sortable, Tour, Button } from
787
788
 
788
789
  <Sortable aria-label="Backlog" items={tasks} onReorder={setTasks} renderItem={(t) => t.title} />
789
790
 
791
+ <SortableGroup onMove={({ item, from, to }) => moveTask(item, from, to)} canDrop={(task, target) => canEnter(task, target.listId)}>
792
+ <Sortable id="backlog" aria-label="Backlog" items={backlog} onReorder={setBacklog} />
793
+ <Sortable id="sprint" aria-label="Sprint" items={sprint} onReorder={setSprint} />
794
+ </SortableGroup>
795
+
790
796
  <Tour open={tourOpen} steps={[{ title: 'Welcome' }, { target: '[data-tour="new-task"]', title: 'Capture work' }]} onClose={() => setTourOpen(false)} />
791
797
  ```
792
798
 
@@ -807,12 +813,13 @@ screen readers (`accessibleTable`), shows `emptyState` for empty data, and disab
807
813
  | [`AreaChart`](doc/AreaChart.md) | Volume over time, optionally `stacked` |
808
814
  | [`DonutChart`](doc/DonutChart.md) | Part-to-whole (`variant="donut"` or `"pie"`, `centerLabel`) |
809
815
  | [`Sparkline`](doc/Sparkline.md) | Word-sized trend for stat cards and table cells |
816
+ | [`ScatterChart`](doc/ScatterChart.md) | Two numeric axes, one point per entity: `x` + `y` keys, optional `index` (entity name) and `category` (series), `xAxisLabel` / `yAxisLabel`; single points sit on padded axes |
810
817
 
811
818
  Shared props: `valueFormatter`, `height`, `showLegend`, `showTooltip`, `showXAxis`, `showYAxis`,
812
819
  `showGrid`, `colors`, `animate`.
813
820
 
814
821
  ```jsx
815
- import { LineChart, DonutChart, Sparkline } from '@dreamtree-org/twreact-ui/charts';
822
+ import { LineChart, DonutChart, Sparkline, ScatterChart } from '@dreamtree-org/twreact-ui/charts';
816
823
 
817
824
  <LineChart
818
825
  data={[{ month: 'Jan', revenue: 4200 }, { month: 'Feb', revenue: 5100 }]}
@@ -823,6 +830,7 @@ import { LineChart, DonutChart, Sparkline } from '@dreamtree-org/twreact-ui/char
823
830
  />
824
831
  <DonutChart data={byStatus} index="status" category="tasks" centerLabel="63 tasks" title="Tasks by status" />
825
832
  <Sparkline data={weekly} category="signups" color="success" title="Signups, last 4 weeks" />
833
+ <ScatterChart data={projects} x="health" y="variance" index="project" category="department" title="Health vs budget variance" />
826
834
  ```
827
835
 
828
836
  ### Rich text (optional entry point)
@@ -981,7 +989,7 @@ function App() {
981
989
 
982
990
  `ThemeProvider` sets `data-theme`, the `.dark` class and `color-scheme` on `<html>`, so `dark:` utilities work whether your `tailwind.config.js` uses `darkMode: 'class'` or a `[data-theme="dark"]` selector.
983
991
 
984
- Surfaces such as `Card`, `Sidebar`, `Navbar`, `Table`, `FootNav` and `Dropdown` use the semantic `bg-surface` / `bg-background` / `border-line` / `text-foreground` / `text-muted` tokens, which switch under `.dark` (or `[data-theme="dark"]`). Re-theme them by overriding the `--dt-surface`, `--dt-background`, `--dt-line`, … variables.
992
+ Surfaces such as `Card`, `Sidebar`, `Navbar`, `Table`, `FootNav`, `Dropdown`, the `Select` / `DatePicker` / `DateRangePicker` triggers and menus, `Accordion`, `Popover`, `Tour`, `Drawer`, `Pagination`, `LocationPicker`, `Form`'s textarea / file button, the chart tooltip and `RichTextEditor` use the semantic `bg-surface` / `bg-background` / `border-line` / `text-foreground` / `text-muted` tokens, which switch under `.dark` (or `[data-theme="dark"]`). Re-theme them by overriding the `--dt-surface`, `--dt-background`, `--dt-line`, … variables.
985
993
 
986
994
  > **Accessibility fixes (1.4.x):** Radio groups keep a single selection when uncontrolled, Rate and DatePicker use one tab stop with arrow-key focus, Dialog/Sidebar/AppShell drawers share one focus trap and scroll lock, Toast announces via `role="status"`, Alert's dismiss button is labelled, and Input shows a visible focus ring in its default state. No props changed.
987
995
 
@@ -131,9 +131,9 @@ The library exports four kinds of things from `@dreamtree-org/twreact-ui`:
131
131
  | **Core** | `Input`, `Button`, `Select`, `Table`, `Form`, `Accordion`, `Checkbox`, `ColorPicker`, `DatePicker`, `DateRangePicker`, `Loader`, `LocationPicker`, `PriceRangePicker`, `ProgressBar`, `Radio`, `Rate`, `RoundedTag`, `Skeleton`, `Switch`, `Tabs`, `ThreeDotPopover`, `Tooltip`, `SpeechToText`, `TextToSpeech`, `Textarea`, `Slider`, `Popover`, `SegmentedControl`, `SwipeableListItem` (swipe-to-reveal row actions), `SearchField` |
132
132
  | **Navigation** | `Sidebar`, `Navbar`, `FootNav`, `Breadcrumbs` |
133
133
  | **Feedback** | `Dialog`, `Toast` (+ `ToastProvider`, `ToastContainer`, `useToast`), `Alert`, `Drawer` (side sheet; `isOpen`/`onClose` like Dialog), `Sheet` (+ `Sheet.Header/Body/Footer`; phone sheet with snap points), `ActionSheet` (iOS action sheet: `actions` + separate Cancel), `Tour` (onboarding spotlight) |
134
- | **Utility** | `Badge`, `Avatar`, `AvatarGroup` (overlapping stack + `max` "+N"), `Card`, `Pagination`, `Stepper`, `FileUpload`, `Condition`, `Carousel`, `Sortable` (drag + keyboard reorder), `PullToRefresh` (touch pull-to-refresh around a scroller) |
134
+ | **Utility** | `Badge`, `Avatar`, `AvatarGroup` (overlapping stack + `max` "+N"), `Card`, `Pagination`, `Stepper`, `FileUpload`, `Condition`, `Carousel`, `Sortable` (drag + keyboard reorder), `SortableGroup` (move items between `Sortable` lists, `canDrop`), `PullToRefresh` (touch pull-to-refresh around a scroller) |
135
135
  | **Blocks** | `AppShell`, `PageHeader`, `StatCard`, `StatusPill`, `EmptyState`, `ErrorState`, `LoadingState`, `ConfirmDialog`, `BottomActionBar` (+ `BottomActionBar.Spacer`) — page-level patterns; build pages from these before composing layouts by hand |
136
- | **Charts** (`@dreamtree-org/twreact-ui/charts`, peer `recharts`) | `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, `Sparkline` — NOT exported from the root |
136
+ | **Charts** (`@dreamtree-org/twreact-ui/charts`, peer `recharts`) | `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, `Sparkline`, `ScatterChart` — NOT exported from the root |
137
137
  | **Rich text** (`@dreamtree-org/twreact-ui/rich-text`, peers `@tiptap/react @tiptap/pm @tiptap/starter-kit`) | `RichTextEditor` — NOT exported from the root |
138
138
 
139
139
  ### Hooks
@@ -232,9 +232,10 @@ When suggesting a component or new variant value, use this exact vocabulary.
232
232
  - `Textarea` — same API as `Input` plus `autoResize`/`maxRows`; never a raw `<textarea>`.
233
233
  - `Slider` — `defaultValue={40}` for one thumb, `[low, high]` for a range; `onChangeEnd` to save after a drag. A value bubble shows while dragging (`showBubble={false}` to hide).
234
234
  - `Sortable` — `items` + `onReorder(newItems)` + `renderItem`; keyboard reordering and announcements are built in. Pass `handle` and spread `handleProps` on a grip for touch screens.
235
+ - `SortableGroup` — for boards / backlog → sprint: wrap the lists, give each `Sortable` an `id` (+ `aria-label`, used in announcements) and handle `onMove({ item, from: { listId, index }, to: { listId, index } })`; pass `canDrop(item, target, from)` (e.g. from a server transition list) so refused columns are marked and announced before the drop instead of reverting after it. Within-list reorders still call each list's `onReorder`. Give lists a `min-h-*` so empty ones can be dropped on.
235
236
  - `PullToRefresh` — wrap a list: `<PullToRefresh onRefresh={() => refetch()} className="h-96">…</PullToRefresh>` (renders the scroller) or pass `scrollRef` to your own. `onRefresh` returns a promise; the spinner spins until it settles. `threshold` (64), `disabled`, `refreshingLabel`. Touch only — keep a refresh button for mouse/keyboard users.
236
237
  - Haptics are opt-in: `haptics` on `Switch` / `Checkbox` (selection tick), `Sheet` (tick on a new snap point) and `ConfirmDialog` (warning on destructive open, success on confirm). Default `false`; never the only signal. For custom cues use `useHaptics().trigger('success')`.
237
- - Charts (`/charts`) — `<LineChart data={rows} index="month" categories={['revenue', 'costs']} />`; same shape for `BarChart` (`stacked`, `horizontal`) and `AreaChart` (`stacked`); `DonutChart` takes `index` (name key) + `category` (value key) + `centerLabel`; `Sparkline` takes `category` + `color`. Colours are tokens (`colors={['primary', 'success-600']}`), never hex. Always pass `title` (accessible name) and, for key charts, a `description` with the takeaway. `valueFormatter` formats tooltip/axis/table values.
238
+ - Charts (`/charts`) — `<LineChart data={rows} index="month" categories={['revenue', 'costs']} />`; same shape for `BarChart` (`stacked`, `horizontal`) and `AreaChart` (`stacked`); `DonutChart` takes `index` (name key) + `category` (value key) + `centerLabel`; `Sparkline` takes `category` + `color`; `ScatterChart` takes `x` + `y` (numeric keys) plus optional `index` (entity name) and `category` (series), e.g. `<ScatterChart data={projects} x="health" y="variance" index="project" category="department" />`. Colours are tokens (`colors={['primary', 'success-600']}`), never hex. Always pass `title` (accessible name) and, for key charts, a `description` with the takeaway. `valueFormatter` formats tooltip/axis/table values.
238
239
  - `RichTextEditor` (`/rich-text`) — `label`/`error`/`helperText` like `Input`; `value` + `onChange(html)` (or `outputFormat="json"`); `toolbar={['bold', 'italic', 'link']}` to trim. Tell the user to **sanitize the HTML server-side**; never render it with `dangerouslySetInnerHTML` unsanitized.
239
240
  - `Tour` — onboarding coach marks: `steps=[{ target: '[data-tour="x"]', title, content, placement }]`, `open`, `onClose(reason)`; a missing target falls back to a centred card.
240
241
 
@@ -2444,6 +2444,118 @@
2444
2444
  }
2445
2445
  }
2446
2446
  },
2447
+ "ScatterChart": {
2448
+ "group": "charts",
2449
+ "import": "@dreamtree-org/twreact-ui/charts",
2450
+ "forwardRef": true,
2451
+ "props": {
2452
+ "data": {
2453
+ "type": "ChartDatum[]",
2454
+ "required": true
2455
+ },
2456
+ "title": {
2457
+ "type": "string",
2458
+ "required": false
2459
+ },
2460
+ "description": {
2461
+ "type": "string",
2462
+ "required": false
2463
+ },
2464
+ "valueFormatter": {
2465
+ "type": "ChartValueFormatter",
2466
+ "required": false,
2467
+ "default": "toLocaleString"
2468
+ },
2469
+ "height": {
2470
+ "type": "number | string",
2471
+ "required": false,
2472
+ "default": "300"
2473
+ },
2474
+ "emptyState": {
2475
+ "type": "ReactNode",
2476
+ "required": false,
2477
+ "default": "\"No data to display\""
2478
+ },
2479
+ "accessibleTable": {
2480
+ "type": "boolean",
2481
+ "required": false,
2482
+ "default": "true"
2483
+ },
2484
+ "animate": {
2485
+ "type": "boolean",
2486
+ "required": false,
2487
+ "default": "true"
2488
+ },
2489
+ "showTooltip": {
2490
+ "type": "boolean",
2491
+ "required": false,
2492
+ "default": "true"
2493
+ },
2494
+ "x": {
2495
+ "type": "string",
2496
+ "required": true
2497
+ },
2498
+ "y": {
2499
+ "type": "string",
2500
+ "required": true
2501
+ },
2502
+ "index": {
2503
+ "type": "string",
2504
+ "required": false
2505
+ },
2506
+ "category": {
2507
+ "type": "string",
2508
+ "required": false
2509
+ },
2510
+ "colors": {
2511
+ "type": "ChartColor[]",
2512
+ "required": false,
2513
+ "default": "primary, success, warning, error, info, secondary, gray"
2514
+ },
2515
+ "xAxisFormatter": {
2516
+ "type": "(value: number) => string",
2517
+ "required": false,
2518
+ "default": "toLocaleString"
2519
+ },
2520
+ "xAxisLabel": {
2521
+ "type": "string",
2522
+ "required": false
2523
+ },
2524
+ "yAxisLabel": {
2525
+ "type": "string",
2526
+ "required": false
2527
+ },
2528
+ "showLegend": {
2529
+ "type": "boolean",
2530
+ "required": false,
2531
+ "default": "true"
2532
+ },
2533
+ "showXAxis": {
2534
+ "type": "boolean",
2535
+ "required": false,
2536
+ "default": "true"
2537
+ },
2538
+ "showYAxis": {
2539
+ "type": "boolean",
2540
+ "required": false,
2541
+ "default": "true"
2542
+ },
2543
+ "showGrid": {
2544
+ "type": "boolean",
2545
+ "required": false,
2546
+ "default": "true"
2547
+ },
2548
+ "yAxisWidth": {
2549
+ "type": "number",
2550
+ "required": false,
2551
+ "default": "48 (36 when the chart is narrower than 400 px)"
2552
+ },
2553
+ "aspectRatio": {
2554
+ "type": "number",
2555
+ "required": false
2556
+ }
2557
+ }
2558
+ },
2447
2559
  "SearchField": {
2448
2560
  "group": "core",
2449
2561
  "import": "@dreamtree-org/twreact-ui",
@@ -3103,6 +3215,29 @@
3103
3215
  "messages": {
3104
3216
  "type": "SortableMessages",
3105
3217
  "required": false
3218
+ },
3219
+ "id": {
3220
+ "type": "string",
3221
+ "required": false
3222
+ }
3223
+ }
3224
+ },
3225
+ "SortableGroup": {
3226
+ "group": "utility",
3227
+ "import": "@dreamtree-org/twreact-ui",
3228
+ "forwardRef": true,
3229
+ "props": {
3230
+ "onMove": {
3231
+ "type": "(move: SortableMove<T>) => void",
3232
+ "required": false
3233
+ },
3234
+ "canDrop": {
3235
+ "type": "(item: T, target: SortableLocation, from: SortableLocation) => boolean",
3236
+ "required": false
3237
+ },
3238
+ "children": {
3239
+ "type": "ReactNode",
3240
+ "required": false
3106
3241
  }
3107
3242
  }
3108
3243
  },
@@ -1,9 +1,10 @@
1
1
  import type * as React from "react";
2
- import type { AreaChartProps, BarChartProps, DonutChartProps, LineChartProps, SparklineProps } from "../types/charts";
2
+ import type { AreaChartProps, BarChartProps, DonutChartProps, LineChartProps, ScatterChartProps, SparklineProps } from "../types/charts";
3
3
  export declare const LineChart: React.ForwardRefExoticComponent<LineChartProps & React.RefAttributes<HTMLDivElement>>;
4
4
  export declare const BarChart: React.ForwardRefExoticComponent<BarChartProps & React.RefAttributes<HTMLDivElement>>;
5
5
  export declare const AreaChart: React.ForwardRefExoticComponent<AreaChartProps & React.RefAttributes<HTMLDivElement>>;
6
6
  export declare const DonutChart: React.ForwardRefExoticComponent<DonutChartProps & React.RefAttributes<HTMLDivElement>>;
7
7
  export declare const Sparkline: React.ForwardRefExoticComponent<SparklineProps & React.RefAttributes<HTMLDivElement>>;
8
+ export declare const ScatterChart: React.ForwardRefExoticComponent<ScatterChartProps & React.RefAttributes<HTMLDivElement>>;
8
9
  export * from "../types/charts";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -11,7 +11,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
11
 
12
12
  var React__default = /*#__PURE__*/_interopDefault(React);
13
13
 
14
- var _excluded$3 = ["className", "title", "description", "defaultTitle", "data", "height", "aspectRatio", "emptyState", "legend", "accessibleTable", "tableColumns", "children", "aria-label"];
14
+ var _excluded$4 = ["className", "title", "description", "defaultTitle", "data", "height", "aspectRatio", "emptyState", "legend", "accessibleTable", "tableColumns", "children", "aria-label"];
15
15
  // The swatch colour arrives as a custom property so a token (`rgb(var(--dt-*))`)
16
16
  // and a resolved rgb() string both work.
17
17
  var swatch = function swatch(size) {
@@ -57,7 +57,7 @@ function ChartTooltipContent(_ref2) {
57
57
  hideLabel = _ref2$hideLabel === void 0 ? false : _ref2$hideLabel;
58
58
  if (!active || !payload || !payload.length) return null;
59
59
  return jsxRuntime.jsxs("div", {
60
- className: "rounded-md border border-gray-200 bg-white px-3 py-2 text-xs text-gray-900 shadow-md dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100",
60
+ className: "rounded-md border border-line bg-surface px-3 py-2 text-xs text-foreground shadow-md",
61
61
  "data-chart-tooltip": "",
62
62
  children: [!hideLabel && label != null && label !== "" && jsxRuntime.jsx("p", {
63
63
  className: "mb-1 font-medium",
@@ -97,11 +97,11 @@ function ChartDataTable(_ref3) {
97
97
  children: caption
98
98
  }), jsxRuntime.jsx("thead", {
99
99
  children: jsxRuntime.jsx("tr", {
100
- children: columns.map(function (c) {
100
+ children: columns.map(function (c, i) {
101
101
  return jsxRuntime.jsx("th", {
102
102
  scope: "col",
103
103
  children: c.label
104
- }, c.key);
104
+ }, "".concat(c.key, "-").concat(i));
105
105
  })
106
106
  })
107
107
  }), jsxRuntime.jsx("tbody", {
@@ -111,9 +111,9 @@ function ChartDataTable(_ref3) {
111
111
  return i === 0 ? jsxRuntime.jsx("th", {
112
112
  scope: "row",
113
113
  children: c.format(row[c.key])
114
- }, c.key) : jsxRuntime.jsx("td", {
114
+ }, "".concat(c.key, "-").concat(i)) : jsxRuntime.jsx("td", {
115
115
  children: c.format(row[c.key])
116
- }, c.key);
116
+ }, "".concat(c.key, "-").concat(i));
117
117
  })
118
118
  }, r);
119
119
  })
@@ -141,7 +141,7 @@ var ChartFrame = /*#__PURE__*/React__default.default.forwardRef(function ChartFr
141
141
  tableColumns = _ref4.tableColumns,
142
142
  children = _ref4.children,
143
143
  ariaLabel = _ref4["aria-label"],
144
- rest = cn._objectWithoutProperties(_ref4, _excluded$3);
144
+ rest = cn._objectWithoutProperties(_ref4, _excluded$4);
145
145
  var descriptionId = React.useId();
146
146
  var name = title || ariaLabel || defaultTitle;
147
147
  if (!Array.isArray(data) || data.length === 0) {
@@ -452,7 +452,7 @@ function usePinnedTooltip() {
452
452
  };
453
453
  }
454
454
 
455
- var _excluded$2 = ["kind", "data", "index", "categories", "colors", "valueFormatter", "xAxisFormatter", "height", "aspectRatio", "showLegend", "showTooltip", "showXAxis", "showYAxis", "showGrid", "yAxisWidth", "curveType", "stacked", "horizontal", "showDots", "connectNulls", "animate", "title", "description", "emptyState", "accessibleTable", "className"],
455
+ var _excluded$3 = ["kind", "data", "index", "categories", "colors", "valueFormatter", "xAxisFormatter", "height", "aspectRatio", "showLegend", "showTooltip", "showXAxis", "showYAxis", "showGrid", "yAxisWidth", "curveType", "stacked", "horizontal", "showDots", "connectNulls", "animate", "title", "description", "emptyState", "accessibleTable", "className"],
456
456
  _excluded2 = ["ref"];
457
457
  var ROOTS = {
458
458
  line: recharts.LineChart,
@@ -577,7 +577,7 @@ var CartesianChart = /*#__PURE__*/React__default.default.forwardRef(function Car
577
577
  _ref2$accessibleTable = _ref2.accessibleTable,
578
578
  accessibleTable = _ref2$accessibleTable === void 0 ? true : _ref2$accessibleTable,
579
579
  className = _ref2.className,
580
- rest = cn._objectWithoutProperties(_ref2, _excluded$2);
580
+ rest = cn._objectWithoutProperties(_ref2, _excluded$3);
581
581
  var _useChartTheme = useChartTheme(categories, colors),
582
582
  chrome = _useChartTheme.chrome,
583
583
  series = _useChartTheme.series;
@@ -747,7 +747,7 @@ var AreaChart = /*#__PURE__*/React__default.default.forwardRef(function (props,
747
747
  });
748
748
  AreaChart.displayName = "AreaChart";
749
749
 
750
- var _excluded$1 = ["data", "index", "category", "colors", "valueFormatter", "variant", "innerRadius", "outerRadius", "centerLabel", "height", "showLegend", "showTooltip", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
750
+ var _excluded$2 = ["data", "index", "category", "colors", "valueFormatter", "variant", "innerRadius", "outerRadius", "centerLabel", "height", "showLegend", "showTooltip", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
751
751
  var DonutChart = /*#__PURE__*/React__default.default.forwardRef(function (_ref, ref) {
752
752
  var data = _ref.data,
753
753
  _ref$index = _ref.index,
@@ -778,7 +778,7 @@ var DonutChart = /*#__PURE__*/React__default.default.forwardRef(function (_ref,
778
778
  _ref$accessibleTable = _ref.accessibleTable,
779
779
  accessibleTable = _ref$accessibleTable === void 0 ? true : _ref$accessibleTable,
780
780
  className = _ref.className,
781
- rest = cn._objectWithoutProperties(_ref, _excluded$1);
781
+ rest = cn._objectWithoutProperties(_ref, _excluded$2);
782
782
  var rows = Array.isArray(data) ? data : [];
783
783
  var names = rows.map(function (row) {
784
784
  return String(row[index]);
@@ -860,7 +860,7 @@ var DonutChart = /*#__PURE__*/React__default.default.forwardRef(function (_ref,
860
860
  });
861
861
  DonutChart.displayName = "DonutChart";
862
862
 
863
- var _excluded = ["data", "category", "index", "color", "type", "valueFormatter", "height", "showTooltip", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
863
+ var _excluded$1 = ["data", "category", "index", "color", "type", "valueFormatter", "height", "showTooltip", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
864
864
  /** A word-sized trend line: no axes, grid or legend — just the shape of the data. */
865
865
  var Sparkline = /*#__PURE__*/React__default.default.forwardRef(function (_ref, ref) {
866
866
  var data = _ref.data,
@@ -886,7 +886,7 @@ var Sparkline = /*#__PURE__*/React__default.default.forwardRef(function (_ref, r
886
886
  _ref$accessibleTable = _ref.accessibleTable,
887
887
  accessibleTable = _ref$accessibleTable === void 0 ? true : _ref$accessibleTable,
888
888
  className = _ref.className,
889
- rest = cn._objectWithoutProperties(_ref, _excluded);
889
+ rest = cn._objectWithoutProperties(_ref, _excluded$1);
890
890
  var _useChartTheme = useChartTheme([category], [color]),
891
891
  series = _useChartTheme.series;
892
892
  var reducedMotion = useReducedMotion();
@@ -964,8 +964,293 @@ var Sparkline = /*#__PURE__*/React__default.default.forwardRef(function (_ref, r
964
964
  });
965
965
  Sparkline.displayName = "Sparkline";
966
966
 
967
+ // Internal to the charts entry point: data shaping for ScatterChart.
968
+ var isFiniteNumber = function isFiniteNumber(v) {
969
+ return typeof v === "number" && Number.isFinite(v);
970
+ };
971
+ var textOf = function textOf(v) {
972
+ return v == null ? "" : String(v);
973
+ };
974
+ /**
975
+ * Axis domain. recharts draws a zero-width scale for a single distinct value, so
976
+ * pad around it; otherwise let recharts pick nice bounds.
977
+ */
978
+ function scatterDomain(values) {
979
+ if (!values.length) return ["auto", "auto"];
980
+ var min = Math.min.apply(Math, cn._toConsumableArray(values));
981
+ var max = Math.max.apply(Math, cn._toConsumableArray(values));
982
+ if (min !== max) return ["auto", "auto"];
983
+ var pad = Math.abs(min) / 2 || 1;
984
+ return [min - pad, max + pad];
985
+ }
986
+ /** Rows with a numeric x and y, split into series by the `category` key (first-seen order). */
987
+ function groupScatter(data, _ref) {
988
+ var x = _ref.x,
989
+ y = _ref.y,
990
+ category = _ref.category;
991
+ var rows = (Array.isArray(data) ? data : []).filter(function (row) {
992
+ return isFiniteNumber(row === null || row === void 0 ? void 0 : row[x]) && isFiniteNumber(row === null || row === void 0 ? void 0 : row[y]);
993
+ });
994
+ var groups = new Map();
995
+ rows.forEach(function (row) {
996
+ var name = category ? textOf(row[category]) : y;
997
+ if (!groups.has(name)) groups.set(name, []);
998
+ groups.get(name).push(row);
999
+ });
1000
+ return {
1001
+ rows: rows,
1002
+ names: cn._toConsumableArray(groups.keys()),
1003
+ groups: groups
1004
+ };
1005
+ }
1006
+
1007
+ /**
1008
+ * Tooltip for one ScatterChart point: the entity (`index`) or series name as the
1009
+ * heading, then the series (when both are set) and the formatted x and y values.
1010
+ */
1011
+ function ScatterTooltipContent(_ref) {
1012
+ var active = _ref.active,
1013
+ payload = _ref.payload,
1014
+ index = _ref.index,
1015
+ category = _ref.category,
1016
+ _ref$colorFor = _ref.colorFor,
1017
+ colorFor = _ref$colorFor === void 0 ? {} : _ref$colorFor,
1018
+ x = _ref.x,
1019
+ y = _ref.y;
1020
+ var row = active && payload && payload.length ? payload[0].payload : null;
1021
+ if (!row) return null;
1022
+ var seriesName = category ? textOf(row[category]) : null;
1023
+ var heading = index ? textOf(row[index]) : seriesName;
1024
+ var lines = [].concat(cn._toConsumableArray(index && seriesName ? [[category, seriesName]] : []), [[x.label, x.format(row[x.key])], [y.label, y.format(row[y.key])]]);
1025
+ return jsxRuntime.jsxs("div", {
1026
+ className: "rounded-md border border-line bg-surface px-3 py-2 text-xs text-foreground shadow-md",
1027
+ "data-chart-tooltip": "",
1028
+ children: [heading && jsxRuntime.jsxs("p", {
1029
+ className: "mb-1 flex items-center gap-2 font-medium",
1030
+ children: [seriesName && jsxRuntime.jsx("span", {
1031
+ className: swatch("h-2 w-2"),
1032
+ style: {
1033
+ "--dt-chart-color": colorFor[seriesName]
1034
+ },
1035
+ "aria-hidden": "true"
1036
+ }), jsxRuntime.jsx("span", {
1037
+ children: heading
1038
+ })]
1039
+ }), jsxRuntime.jsx("ul", {
1040
+ className: "space-y-0.5",
1041
+ children: lines.map(function (_ref2) {
1042
+ var _ref3 = cn._slicedToArray(_ref2, 2),
1043
+ name = _ref3[0],
1044
+ value = _ref3[1];
1045
+ return jsxRuntime.jsxs("li", {
1046
+ className: "flex items-center gap-2",
1047
+ children: [jsxRuntime.jsx("span", {
1048
+ className: "text-muted",
1049
+ children: name
1050
+ }), jsxRuntime.jsx("span", {
1051
+ className: "ml-auto pl-3 font-medium tabular-nums",
1052
+ children: value
1053
+ })]
1054
+ }, name);
1055
+ })
1056
+ })]
1057
+ });
1058
+ }
1059
+
1060
+ var _excluded = ["data", "x", "y", "index", "category", "colors", "valueFormatter", "xAxisFormatter", "xAxisLabel", "yAxisLabel", "height", "aspectRatio", "showLegend", "showTooltip", "showXAxis", "showYAxis", "showGrid", "yAxisWidth", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
1061
+ var ScatterChart = /*#__PURE__*/React__default.default.forwardRef(function ScatterChart(_ref, ref) {
1062
+ var data = _ref.data,
1063
+ x = _ref.x,
1064
+ y = _ref.y,
1065
+ index = _ref.index,
1066
+ category = _ref.category,
1067
+ colors = _ref.colors,
1068
+ _ref$valueFormatter = _ref.valueFormatter,
1069
+ valueFormatter = _ref$valueFormatter === void 0 ? defaultValueFormatter : _ref$valueFormatter,
1070
+ _ref$xAxisFormatter = _ref.xAxisFormatter,
1071
+ xAxisFormatter = _ref$xAxisFormatter === void 0 ? defaultValueFormatter : _ref$xAxisFormatter,
1072
+ xAxisLabel = _ref.xAxisLabel,
1073
+ yAxisLabel = _ref.yAxisLabel,
1074
+ _ref$height = _ref.height,
1075
+ height = _ref$height === void 0 ? 300 : _ref$height,
1076
+ aspectRatio = _ref.aspectRatio,
1077
+ _ref$showLegend = _ref.showLegend,
1078
+ showLegend = _ref$showLegend === void 0 ? true : _ref$showLegend,
1079
+ _ref$showTooltip = _ref.showTooltip,
1080
+ showTooltip = _ref$showTooltip === void 0 ? true : _ref$showTooltip,
1081
+ _ref$showXAxis = _ref.showXAxis,
1082
+ showXAxis = _ref$showXAxis === void 0 ? true : _ref$showXAxis,
1083
+ _ref$showYAxis = _ref.showYAxis,
1084
+ showYAxis = _ref$showYAxis === void 0 ? true : _ref$showYAxis,
1085
+ _ref$showGrid = _ref.showGrid,
1086
+ showGrid = _ref$showGrid === void 0 ? true : _ref$showGrid,
1087
+ yAxisWidth = _ref.yAxisWidth,
1088
+ _ref$animate = _ref.animate,
1089
+ animate = _ref$animate === void 0 ? true : _ref$animate,
1090
+ title = _ref.title,
1091
+ description = _ref.description,
1092
+ emptyState = _ref.emptyState,
1093
+ _ref$accessibleTable = _ref.accessibleTable,
1094
+ accessibleTable = _ref$accessibleTable === void 0 ? true : _ref$accessibleTable,
1095
+ className = _ref.className,
1096
+ rest = cn._objectWithoutProperties(_ref, _excluded);
1097
+ var _groupScatter = groupScatter(data, {
1098
+ x: x,
1099
+ y: y,
1100
+ category: category
1101
+ }),
1102
+ rows = _groupScatter.rows,
1103
+ names = _groupScatter.names,
1104
+ groups = _groupScatter.groups;
1105
+ var _useChartTheme = useChartTheme(names, colors),
1106
+ chrome = _useChartTheme.chrome,
1107
+ series = _useChartTheme.series;
1108
+ var reducedMotion = useReducedMotion();
1109
+ var chartId = useChartId();
1110
+ var _useElementWidth = useElementWidth(),
1111
+ _useElementWidth2 = cn._slicedToArray(_useElementWidth, 2),
1112
+ measureRef = _useElementWidth2[0],
1113
+ width = _useElementWidth2[1];
1114
+ var tick = {
1115
+ fill: chrome.axis,
1116
+ fontSize: 12
1117
+ };
1118
+ var axisTitle = function axisTitle(value, angle) {
1119
+ return value ? {
1120
+ value: value,
1121
+ angle: angle,
1122
+ position: angle ? "insideLeft" : "insideBottom",
1123
+ offset: angle ? 10 : -4,
1124
+ fill: chrome.axis,
1125
+ fontSize: 12
1126
+ } : undefined;
1127
+ };
1128
+ var xLabel = xAxisLabel || x;
1129
+ var yLabel = yAxisLabel || y;
1130
+ return jsxRuntime.jsx(ChartFrame, cn._objectSpread2(cn._objectSpread2({
1131
+ ref: ref,
1132
+ className: className,
1133
+ title: title,
1134
+ description: description,
1135
+ defaultTitle: "Scatter chart",
1136
+ data: rows,
1137
+ height: height,
1138
+ aspectRatio: aspectRatio,
1139
+ emptyState: emptyState,
1140
+ accessibleTable: accessibleTable,
1141
+ legend: showLegend && category ? names.map(function (name, i) {
1142
+ return {
1143
+ name: name,
1144
+ color: series[i]
1145
+ };
1146
+ }) : null,
1147
+ tableColumns: [].concat(cn._toConsumableArray(index ? [{
1148
+ key: index,
1149
+ label: index,
1150
+ format: textOf
1151
+ }] : []), cn._toConsumableArray(category && category !== index ? [{
1152
+ key: category,
1153
+ label: category,
1154
+ format: textOf
1155
+ }] : []), [{
1156
+ key: x,
1157
+ label: xLabel,
1158
+ format: xAxisFormatter
1159
+ }, {
1160
+ key: y,
1161
+ label: yLabel,
1162
+ format: valueFormatter
1163
+ }])
1164
+ }, rest), {}, {
1165
+ children: jsxRuntime.jsx("div", {
1166
+ className: "h-full w-full",
1167
+ ref: measureRef,
1168
+ children: jsxRuntime.jsx(recharts.ResponsiveContainer, {
1169
+ width: "100%",
1170
+ height: "100%",
1171
+ minWidth: 0,
1172
+ children: jsxRuntime.jsxs(recharts.ScatterChart, {
1173
+ id: chartId,
1174
+ margin: {
1175
+ top: 8,
1176
+ right: 8,
1177
+ bottom: xAxisLabel ? 16 : 0,
1178
+ left: 0
1179
+ },
1180
+ accessibilityLayer: false,
1181
+ children: [showGrid && jsxRuntime.jsx(recharts.CartesianGrid, {
1182
+ stroke: chrome.grid,
1183
+ strokeDasharray: "3 3"
1184
+ }), jsxRuntime.jsx(recharts.XAxis, {
1185
+ type: "number",
1186
+ dataKey: x,
1187
+ name: xLabel,
1188
+ domain: scatterDomain(rows.map(function (row) {
1189
+ return row[x];
1190
+ })),
1191
+ tick: tick,
1192
+ tickLine: false,
1193
+ axisLine: false,
1194
+ tickFormatter: xAxisFormatter,
1195
+ minTickGap: tickGapFor(width),
1196
+ hide: !showXAxis,
1197
+ label: axisTitle(xAxisLabel, 0)
1198
+ }), jsxRuntime.jsx(recharts.YAxis, {
1199
+ type: "number",
1200
+ dataKey: y,
1201
+ name: yLabel,
1202
+ domain: scatterDomain(rows.map(function (row) {
1203
+ return row[y];
1204
+ })),
1205
+ tick: tick,
1206
+ tickLine: false,
1207
+ axisLine: false,
1208
+ tickFormatter: valueFormatter,
1209
+ width: yAxisWidth !== null && yAxisWidth !== void 0 ? yAxisWidth : yAxisWidthFor(width),
1210
+ hide: !showYAxis,
1211
+ label: axisTitle(yAxisLabel, -90)
1212
+ }), showTooltip && jsxRuntime.jsx(recharts.Tooltip, {
1213
+ cursor: {
1214
+ stroke: chrome.grid,
1215
+ strokeDasharray: "3 3"
1216
+ },
1217
+ isAnimationActive: false,
1218
+ content: jsxRuntime.jsx(ScatterTooltipContent, {
1219
+ index: index,
1220
+ category: category,
1221
+ colorFor: Object.fromEntries(names.map(function (name, i) {
1222
+ return [name, series[i]];
1223
+ })),
1224
+ x: {
1225
+ key: x,
1226
+ label: xLabel,
1227
+ format: xAxisFormatter
1228
+ },
1229
+ y: {
1230
+ key: y,
1231
+ label: yLabel,
1232
+ format: valueFormatter
1233
+ }
1234
+ })
1235
+ }), names.map(function (name, i) {
1236
+ return jsxRuntime.jsx(recharts.Scatter, {
1237
+ id: "".concat(chartId, "-").concat(i),
1238
+ name: name,
1239
+ data: groups.get(name),
1240
+ fill: series[i],
1241
+ isAnimationActive: animate && !reducedMotion
1242
+ }, name);
1243
+ })]
1244
+ })
1245
+ })
1246
+ })
1247
+ }));
1248
+ });
1249
+ ScatterChart.displayName = "ScatterChart";
1250
+
967
1251
  exports.AreaChart = AreaChart;
968
1252
  exports.BarChart = BarChart;
969
1253
  exports.DonutChart = DonutChart;
970
1254
  exports.LineChart = LineChart;
1255
+ exports.ScatterChart = ScatterChart;
971
1256
  exports.Sparkline = Sparkline;