@dreamtree-org/twreact-ui 1.3.10 → 1.3.11

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 (93) hide show
  1. package/README.md +30 -0
  2. package/ai-skills/dreamtree-ui.md +12 -7
  3. package/dist/ai-schema.json +137 -21
  4. package/dist/charts/index.js +195 -66
  5. package/dist/components/charts/CartesianChart.d.ts.map +1 -1
  6. package/dist/components/charts/ChartFrame.d.ts.map +1 -1
  7. package/dist/components/charts/useChartLayout.d.ts +25 -0
  8. package/dist/components/charts/useChartLayout.d.ts.map +1 -0
  9. package/dist/components/core/Button.d.ts.map +1 -1
  10. package/dist/components/core/Checkbox.d.ts.map +1 -1
  11. package/dist/components/core/ColorPicker.d.ts.map +1 -1
  12. package/dist/components/core/Input.d.ts.map +1 -1
  13. package/dist/components/core/Loader.d.ts.map +1 -1
  14. package/dist/components/core/LocationPicker.d.ts.map +1 -1
  15. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  16. package/dist/components/core/Radio.d.ts.map +1 -1
  17. package/dist/components/core/Rate.d.ts.map +1 -1
  18. package/dist/components/core/RoundedTag.d.ts.map +1 -1
  19. package/dist/components/core/Skeleton.d.ts.map +1 -1
  20. package/dist/components/core/Slider.d.ts.map +1 -1
  21. package/dist/components/core/SpeechToText.d.ts.map +1 -1
  22. package/dist/components/core/Switch.d.ts.map +1 -1
  23. package/dist/components/core/Tabs.d.ts +2 -5
  24. package/dist/components/core/Tabs.d.ts.map +1 -1
  25. package/dist/components/core/Textarea.d.ts.map +1 -1
  26. package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
  27. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  28. package/dist/components/utility/Avatar.d.ts +8 -0
  29. package/dist/components/utility/Avatar.d.ts.map +1 -1
  30. package/dist/components/utility/AvatarGroup.d.ts +4 -0
  31. package/dist/components/utility/AvatarGroup.d.ts.map +1 -0
  32. package/dist/components/utility/Badge.d.ts.map +1 -1
  33. package/dist/components/utility/Card.d.ts.map +1 -1
  34. package/dist/components/utility/Carousel.d.ts.map +1 -1
  35. package/dist/components/utility/FileUpload.d.ts.map +1 -1
  36. package/dist/components/utility/Pagination.d.ts.map +1 -1
  37. package/dist/components/utility/Sortable.d.ts.map +1 -1
  38. package/dist/components/utility/Stepper.d.ts.map +1 -1
  39. package/dist/esm/components/blocks/EmptyState.js +1 -1
  40. package/dist/esm/components/blocks/ErrorState.js +1 -1
  41. package/dist/esm/components/blocks/LoadingState.js +4 -4
  42. package/dist/esm/components/blocks/StatCard.js +6 -6
  43. package/dist/esm/components/blocks/StatusPill.js +5 -8
  44. package/dist/esm/components/charts/CartesianChart.js +85 -62
  45. package/dist/esm/components/charts/ChartFrame.js +12 -5
  46. package/dist/esm/components/charts/useChartLayout.js +105 -0
  47. package/dist/esm/components/core/Button.js +49 -25
  48. package/dist/esm/components/core/Checkbox.js +71 -45
  49. package/dist/esm/components/core/ColorPicker.js +31 -42
  50. package/dist/esm/components/core/Input.js +89 -22
  51. package/dist/esm/components/core/Loader.js +30 -44
  52. package/dist/esm/components/core/LocationPicker.js +82 -16
  53. package/dist/esm/components/core/ProgressBar.js +8 -12
  54. package/dist/esm/components/core/Radio.js +10 -12
  55. package/dist/esm/components/core/Rate.js +72 -4
  56. package/dist/esm/components/core/RoundedTag.js +5 -5
  57. package/dist/esm/components/core/Skeleton.js +13 -14
  58. package/dist/esm/components/core/Slider.js +24 -6
  59. package/dist/esm/components/core/SpeechToText.js +68 -16
  60. package/dist/esm/components/core/Switch.js +88 -16
  61. package/dist/esm/components/core/Tabs.js +180 -33
  62. package/dist/esm/components/core/Textarea.js +10 -2
  63. package/dist/esm/components/navigation/Breadcrumbs.js +97 -35
  64. package/dist/esm/components/navigation/FootNav.js +102 -13
  65. package/dist/esm/components/utility/Avatar.js +14 -12
  66. package/dist/esm/components/utility/AvatarGroup.js +56 -0
  67. package/dist/esm/components/utility/Badge.js +43 -23
  68. package/dist/esm/components/utility/Card.js +32 -8
  69. package/dist/esm/components/utility/Carousel.js +139 -29
  70. package/dist/esm/components/utility/FileUpload.js +106 -31
  71. package/dist/esm/components/utility/Pagination.js +31 -13
  72. package/dist/esm/components/utility/Sortable.js +6 -2
  73. package/dist/esm/components/utility/Stepper.js +110 -47
  74. package/dist/esm/hooks/useSliderValues.js +8 -2
  75. package/dist/esm/hooks/useSortable.js +107 -5
  76. package/dist/esm/index.js +1 -0
  77. package/dist/esm/utils/touchTarget.js +4 -1
  78. package/dist/hooks/useSliderValues.d.ts +6 -2
  79. package/dist/hooks/useSliderValues.d.ts.map +1 -1
  80. package/dist/hooks/useSortable.d.ts +11 -1
  81. package/dist/hooks/useSortable.d.ts.map +1 -1
  82. package/dist/index.css +1 -1
  83. package/dist/index.d.ts +3 -2
  84. package/dist/index.esm.css +1 -1
  85. package/dist/index.esm.js +2341 -1191
  86. package/dist/index.js +2341 -1190
  87. package/dist/types/charts.d.ts +3 -1
  88. package/dist/types/charts.d.ts.map +1 -1
  89. package/dist/types/index.d.ts +56 -7
  90. package/dist/types/index.d.ts.map +1 -1
  91. package/doc/README.md +1 -0
  92. package/mcp/catalog.snapshot.json +279 -80
  93. package/package.json +1 -1
@@ -11,12 +11,12 @@ var _excluded = ["label", "value", "icon", "tone", "change", "loading", "classNa
11
11
  // Extracted from PracticePro/components/ui/StatCard.tsx (28 imports), with tones mapped to the
12
12
  // semantic scales instead of product colours. Class names are written out in full so Tailwind keeps them.
13
13
  var TONES = {
14
- primary: 'bg-primary-50 text-primary-600',
15
- secondary: 'bg-secondary-100 text-secondary-600',
16
- success: 'bg-success-50 text-success-600',
17
- warning: 'bg-warning-50 text-warning-600',
18
- error: 'bg-error-50 text-error-600',
19
- info: 'bg-info-50 text-info-600'
14
+ primary: 'bg-primary-50 text-primary-600 dark:bg-primary-900/40 dark:text-primary-300',
15
+ secondary: 'bg-secondary-100 text-secondary-600 dark:bg-secondary-800/60 dark:text-secondary-300',
16
+ success: 'bg-success-50 text-success-600 dark:bg-success-900/40 dark:text-success-300',
17
+ warning: 'bg-warning-50 text-warning-600 dark:bg-warning-900/40 dark:text-warning-300',
18
+ error: 'bg-error-50 text-error-600 dark:bg-error-900/40 dark:text-error-300',
19
+ info: 'bg-info-50 text-info-600 dark:bg-info-900/40 dark:text-info-300'
20
20
  };
21
21
  var StatCard = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
22
22
  var _change$goodWhenUp, _change$unit;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
- import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { jsx } from 'react/jsx-runtime';
4
4
  import React from 'react';
5
5
  import { cn } from '../../utils/cn.js';
6
6
  import Badge from '../utility/Badge.js';
@@ -37,17 +37,14 @@ var StatusPill = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
37
37
  var resolvedTone = (entry === null || entry === void 0 ? void 0 : entry.tone) || tone || 'neutral';
38
38
  var label = (_ref2 = children !== null && children !== void 0 ? children : entry === null || entry === void 0 ? void 0 : entry.label) !== null && _ref2 !== void 0 ? _ref2 : status != null ? humanizeStatus(status) : null;
39
39
  var resolvedIcon = icon !== null && icon !== void 0 ? icon : entry === null || entry === void 0 ? void 0 : entry.icon;
40
- return jsxs(Badge, _objectSpread2(_objectSpread2({
40
+ return jsx(Badge, _objectSpread2(_objectSpread2({
41
41
  ref: ref,
42
42
  variant: TONE_TO_VARIANT[resolvedTone] || 'secondary',
43
43
  size: "sm",
44
- className: cn('gap-1.5 whitespace-nowrap', className)
44
+ className: cn('gap-1.5 whitespace-nowrap', className),
45
+ icon: resolvedIcon
45
46
  }, props), {}, {
46
- children: [resolvedIcon && jsx("span", {
47
- className: "inline-flex h-3.5 w-3.5 items-center",
48
- "aria-hidden": "true",
49
- children: resolvedIcon
50
- }), label]
47
+ children: label
51
48
  }));
52
49
  });
53
50
  StatusPill.displayName = 'StatusPill';
@@ -1,13 +1,15 @@
1
1
  'use client';
2
- import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
4
  import React from 'react';
5
5
  import { ResponsiveContainer, AreaChart, BarChart, LineChart, CartesianGrid, XAxis, YAxis, Tooltip, Bar, Area, Line } from 'recharts';
6
6
  import { ChartFrame, ChartTooltipContent } from './ChartFrame.js';
7
7
  import { useChartTheme, useChartId, defaultValueFormatter } from './chartTheme.js';
8
+ import { useElementWidth, usePinnedTooltip, yAxisWidthFor, tickGapFor } from './useChartLayout.js';
8
9
  import { useReducedMotion } from '../../hooks/useReducedMotion.js';
9
10
 
10
- var _excluded = ["kind", "data", "index", "categories", "colors", "valueFormatter", "xAxisFormatter", "height", "showLegend", "showTooltip", "showXAxis", "showYAxis", "showGrid", "yAxisWidth", "curveType", "stacked", "horizontal", "showDots", "connectNulls", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
11
+ var _excluded = ["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"],
12
+ _excluded2 = ["ref"];
11
13
  var ROOTS = {
12
14
  line: LineChart,
13
15
  bar: BarChart,
@@ -101,6 +103,7 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
101
103
  xAxisFormatter = _ref2.xAxisFormatter,
102
104
  _ref2$height = _ref2.height,
103
105
  height = _ref2$height === void 0 ? 300 : _ref2$height,
106
+ aspectRatio = _ref2.aspectRatio,
104
107
  _ref2$showLegend = _ref2.showLegend,
105
108
  showLegend = _ref2$showLegend === void 0 ? true : _ref2$showLegend,
106
109
  _ref2$showTooltip = _ref2.showTooltip,
@@ -111,8 +114,7 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
111
114
  showYAxis = _ref2$showYAxis === void 0 ? true : _ref2$showYAxis,
112
115
  _ref2$showGrid = _ref2.showGrid,
113
116
  showGrid = _ref2$showGrid === void 0 ? true : _ref2$showGrid,
114
- _ref2$yAxisWidth = _ref2.yAxisWidth,
115
- yAxisWidth = _ref2$yAxisWidth === void 0 ? 48 : _ref2$yAxisWidth,
117
+ yAxisWidth = _ref2.yAxisWidth,
116
118
  _ref2$curveType = _ref2.curveType,
117
119
  curveType = _ref2$curveType === void 0 ? "monotone" : _ref2$curveType,
118
120
  _ref2$stacked = _ref2.stacked,
@@ -147,6 +149,20 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
147
149
  var formatIndex = xAxisFormatter || function (v) {
148
150
  return v == null ? "" : String(v);
149
151
  };
152
+ var _useElementWidth = useElementWidth(),
153
+ _useElementWidth2 = _slicedToArray(_useElementWidth, 2),
154
+ measureRef = _useElementWidth2[0],
155
+ width = _useElementWidth2[1];
156
+ var pin = usePinnedTooltip(showTooltip);
157
+ var _pin$wrapperProps = pin.wrapperProps,
158
+ pinRef = _pin$wrapperProps.ref,
159
+ pinWrapperProps = _objectWithoutProperties(_pin$wrapperProps, _excluded2);
160
+ // An explicit yAxisWidth always wins; otherwise narrow charts give the plot more room.
161
+ var valueAxisWidth = yAxisWidth !== null && yAxisWidth !== void 0 ? yAxisWidth : yAxisWidthFor(width);
162
+ var setWrapperNode = React.useCallback(function (node) {
163
+ measureRef.current = node;
164
+ pinRef.current = node;
165
+ }, [measureRef, pinRef]);
150
166
  var categoryAxis = {
151
167
  dataKey: index,
152
168
  tick: tick,
@@ -154,7 +170,7 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
154
170
  axisLine: false,
155
171
  tickFormatter: xAxisFormatter,
156
172
  hide: !showXAxis,
157
- minTickGap: 8
173
+ minTickGap: tickGapFor(width)
158
174
  };
159
175
  var valueAxis = {
160
176
  tick: tick,
@@ -162,7 +178,7 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
162
178
  axisLine: false,
163
179
  tickFormatter: valueFormatter,
164
180
  hide: !showYAxis,
165
- width: yAxisWidth
181
+ width: valueAxisWidth
166
182
  };
167
183
  return jsx(ChartFrame, _objectSpread2(_objectSpread2({
168
184
  ref: ref,
@@ -172,6 +188,7 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
172
188
  defaultTitle: TITLES[kind],
173
189
  data: data,
174
190
  height: height,
191
+ aspectRatio: aspectRatio,
175
192
  emptyState: emptyState,
176
193
  accessibleTable: accessibleTable,
177
194
  legend: showLegend ? categories.map(function (c, i) {
@@ -192,64 +209,70 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
192
209
  };
193
210
  })))
194
211
  }, rest), {}, {
195
- children: jsx(ResponsiveContainer, {
196
- width: "100%",
197
- height: "100%",
198
- minWidth: 0,
199
- children: jsxs(Root, {
200
- id: chartId,
201
- data: data,
202
- layout: isHorizontalBars ? "vertical" : "horizontal",
203
- margin: {
204
- top: 8,
205
- right: 8,
206
- bottom: 0,
207
- left: 0
208
- },
209
- accessibilityLayer: false,
210
- children: [showGrid && jsx(CartesianGrid, {
211
- stroke: chrome.grid,
212
- strokeDasharray: "3 3",
213
- vertical: isHorizontalBars,
214
- horizontal: !isHorizontalBars
215
- }), isHorizontalBars ? jsx(XAxis, _objectSpread2(_objectSpread2({
216
- type: "number"
217
- }, valueAxis), {}, {
218
- hide: !showXAxis,
219
- width: undefined
220
- })) : jsx(XAxis, _objectSpread2({}, categoryAxis)), isHorizontalBars ? jsx(YAxis, _objectSpread2(_objectSpread2({
221
- type: "category"
222
- }, categoryAxis), {}, {
223
- hide: !showYAxis,
224
- width: yAxisWidth,
225
- interval: 0
226
- })) : jsx(YAxis, _objectSpread2({}, valueAxis)), showTooltip && jsx(Tooltip, {
227
- cursor: kind === "bar" ? {
228
- fill: chrome.grid,
229
- fillOpacity: 0.4
230
- } : {
231
- stroke: chrome.grid
212
+ children: jsx("div", _objectSpread2(_objectSpread2({
213
+ className: "h-full w-full",
214
+ ref: setWrapperNode
215
+ }, pinWrapperProps), {}, {
216
+ children: jsx(ResponsiveContainer, {
217
+ width: "100%",
218
+ height: "100%",
219
+ minWidth: 0,
220
+ children: jsxs(Root, {
221
+ id: chartId,
222
+ onClick: pin.onChartClick,
223
+ data: data,
224
+ layout: isHorizontalBars ? "vertical" : "horizontal",
225
+ margin: {
226
+ top: 8,
227
+ right: 8,
228
+ bottom: 0,
229
+ left: 0
232
230
  },
233
- isAnimationActive: false,
234
- content: jsx(ChartTooltipContent, {
235
- valueFormatter: valueFormatter
236
- })
237
- }), categories.map(function (category, i) {
238
- return renderSeries(kind, {
239
- id: "".concat(chartId, "-").concat(i),
240
- category: category,
241
- color: series[i],
242
- curve: curve,
243
- stacked: stacked,
244
- showDots: showDots,
245
- connectNulls: connectNulls,
246
- animate: animate && !reducedMotion,
247
- horizontal: isHorizontalBars,
248
- barRadius: 4
249
- });
250
- })]
231
+ accessibilityLayer: false,
232
+ children: [showGrid && jsx(CartesianGrid, {
233
+ stroke: chrome.grid,
234
+ strokeDasharray: "3 3",
235
+ vertical: isHorizontalBars,
236
+ horizontal: !isHorizontalBars
237
+ }), isHorizontalBars ? jsx(XAxis, _objectSpread2(_objectSpread2({
238
+ type: "number"
239
+ }, valueAxis), {}, {
240
+ hide: !showXAxis,
241
+ width: undefined
242
+ })) : jsx(XAxis, _objectSpread2({}, categoryAxis)), isHorizontalBars ? jsx(YAxis, _objectSpread2(_objectSpread2({
243
+ type: "category"
244
+ }, categoryAxis), {}, {
245
+ hide: !showYAxis,
246
+ width: valueAxisWidth,
247
+ interval: 0
248
+ })) : jsx(YAxis, _objectSpread2({}, valueAxis)), showTooltip && jsx(Tooltip, _objectSpread2({
249
+ cursor: kind === "bar" ? {
250
+ fill: chrome.grid,
251
+ fillOpacity: 0.4
252
+ } : {
253
+ stroke: chrome.grid
254
+ },
255
+ isAnimationActive: false,
256
+ content: jsx(ChartTooltipContent, {
257
+ valueFormatter: valueFormatter
258
+ })
259
+ }, pin.tooltipProps)), categories.map(function (category, i) {
260
+ return renderSeries(kind, {
261
+ id: "".concat(chartId, "-").concat(i),
262
+ category: category,
263
+ color: series[i],
264
+ curve: curve,
265
+ stacked: stacked,
266
+ showDots: showDots,
267
+ connectNulls: connectNulls,
268
+ animate: animate && !reducedMotion,
269
+ horizontal: isHorizontalBars,
270
+ barRadius: 4
271
+ });
272
+ })]
273
+ })
251
274
  })
252
- })
275
+ }))
253
276
  }));
254
277
  });
255
278
 
@@ -4,14 +4,19 @@ import { jsx, jsxs } from 'react/jsx-runtime';
4
4
  import React, { useId } from 'react';
5
5
  import { cn } from '../../utils/cn.js';
6
6
 
7
- var _excluded = ["className", "title", "description", "defaultTitle", "data", "height", "emptyState", "legend", "accessibleTable", "tableColumns", "children", "aria-label"];
7
+ var _excluded = ["className", "title", "description", "defaultTitle", "data", "height", "aspectRatio", "emptyState", "legend", "accessibleTable", "tableColumns", "children", "aria-label"];
8
8
  // The swatch colour arrives as a custom property so a token (`rgb(var(--dt-*))`)
9
9
  // and a resolved rgb() string both work.
10
10
  var swatch = function swatch(size) {
11
11
  return cn("inline-block shrink-0 rounded-full bg-[color:var(--dt-chart-color)]", size);
12
12
  };
13
- var sizeStyle = function sizeStyle(height) {
14
- return {
13
+ // `aspectRatio` (e.g. 16 / 9), when given, replaces the fixed height so the chart
14
+ // scales with its container width.
15
+ var sizeStyle = function sizeStyle(height, aspectRatio) {
16
+ return aspectRatio ? {
17
+ aspectRatio: String(aspectRatio),
18
+ width: "100%"
19
+ } : {
15
20
  height: typeof height === "number" ? "".concat(height, "px") : height
16
21
  };
17
22
  };
@@ -46,6 +51,7 @@ function ChartTooltipContent(_ref2) {
46
51
  if (!active || !payload || !payload.length) return null;
47
52
  return jsxs("div", {
48
53
  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",
54
+ "data-chart-tooltip": "",
49
55
  children: [!hideLabel && label != null && label !== "" && jsx("p", {
50
56
  className: "mb-1 font-medium",
51
57
  children: label
@@ -119,6 +125,7 @@ var ChartFrame = /*#__PURE__*/React.forwardRef(function ChartFrame(_ref4, ref) {
119
125
  defaultTitle = _ref4.defaultTitle,
120
126
  data = _ref4.data,
121
127
  height = _ref4.height,
128
+ aspectRatio = _ref4.aspectRatio,
122
129
  _ref4$emptyState = _ref4.emptyState,
123
130
  emptyState = _ref4$emptyState === void 0 ? "No data to display" : _ref4$emptyState,
124
131
  legend = _ref4.legend,
@@ -134,7 +141,7 @@ var ChartFrame = /*#__PURE__*/React.forwardRef(function ChartFrame(_ref4, ref) {
134
141
  return jsx("div", _objectSpread2(_objectSpread2({
135
142
  ref: ref,
136
143
  className: cn("flex w-full items-center justify-center rounded-md border border-dashed border-gray-300 text-sm text-gray-500 dark:border-gray-700 dark:text-gray-400", className),
137
- style: sizeStyle(height),
144
+ style: sizeStyle(height, aspectRatio),
138
145
  role: "status",
139
146
  "aria-label": name,
140
147
  "data-empty": "true"
@@ -151,7 +158,7 @@ var ChartFrame = /*#__PURE__*/React.forwardRef(function ChartFrame(_ref4, ref) {
151
158
  "aria-label": name,
152
159
  "aria-describedby": description ? descriptionId : undefined,
153
160
  className: "w-full text-gray-500 dark:text-gray-400",
154
- style: sizeStyle(height),
161
+ style: sizeStyle(height, aspectRatio),
155
162
  children: children
156
163
  }), description && jsx("p", {
157
164
  id: descriptionId,
@@ -0,0 +1,105 @@
1
+ 'use client';
2
+ import { slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { useRef, useState, useEffect, useCallback } from 'react';
4
+
5
+ // Internal to the charts entry point. Small-screen helpers for the cartesian
6
+ // charts: measured width (for adaptive ticks / axis width) and a tooltip that a
7
+ // tap can pin open on touch screens.
8
+ /** Gap (px) recharts keeps between x-axis ticks: wider on narrow charts so labels don't collide. */
9
+ function tickGapFor(width) {
10
+ if (!width) return 8;
11
+ if (width < 360) return 32;
12
+ if (width < 640) return 16;
13
+ return 8;
14
+ }
15
+ /** Default value-axis width (px) when the consumer didn't set `yAxisWidth`. */
16
+ function yAxisWidthFor(width) {
17
+ if (!width) return 48;
18
+ return width < 400 ? 36 : 48;
19
+ }
20
+ /** Tracks the rendered width of `ref`'s element. `0` until measured. */
21
+ function useElementWidth() {
22
+ var ref = useRef(null);
23
+ var _useState = useState(0),
24
+ _useState2 = _slicedToArray(_useState, 2),
25
+ width = _useState2[0],
26
+ setWidth = _useState2[1];
27
+ useEffect(function () {
28
+ var node = ref.current;
29
+ if (!node) return undefined;
30
+ var measure = function measure() {
31
+ return setWidth(Math.round(node.getBoundingClientRect().width || 0));
32
+ };
33
+ measure();
34
+ if (typeof ResizeObserver === "undefined") return undefined;
35
+ var observer = new ResizeObserver(measure);
36
+ observer.observe(node);
37
+ return function () {
38
+ return observer.disconnect();
39
+ };
40
+ }, []);
41
+ return [ref, width];
42
+ }
43
+ var readIndex = function readIndex(state) {
44
+ var _state$activeTooltipI;
45
+ var raw = (_state$activeTooltipI = state === null || state === void 0 ? void 0 : state.activeTooltipIndex) !== null && _state$activeTooltipI !== void 0 ? _state$activeTooltipI : state === null || state === void 0 ? void 0 : state.activeIndex;
46
+ if (raw === undefined || raw === null || raw === "") return undefined;
47
+ var n = Number(raw);
48
+ return Number.isNaN(n) ? raw : n;
49
+ };
50
+ /**
51
+ * Tap-to-pin tooltip for touch. A tap on the chart pins the tooltip at the
52
+ * tapped point; a second tap on the chart, or a tap outside it, unpins it.
53
+ * Mouse and pen keep the normal hover tooltip.
54
+ *
55
+ * Returns props for a wrapper element, an `onChartClick` for the recharts root
56
+ * and `tooltipProps` to spread on `<Tooltip>`.
57
+ */
58
+ function usePinnedTooltip() {
59
+ var enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
60
+ var wrapperRef = useRef(null);
61
+ var pointerType = useRef("mouse");
62
+ var _useState3 = useState(null),
63
+ _useState4 = _slicedToArray(_useState3, 2),
64
+ pinned = _useState4[0],
65
+ setPinned = _useState4[1]; // null | { index }
66
+ var onPointerDownCapture = useCallback(function (e) {
67
+ pointerType.current = e.pointerType || "mouse";
68
+ }, []);
69
+ var toggle = useCallback(function (state) {
70
+ if (!enabled || pointerType.current !== "touch") return;
71
+ setPinned(function (current) {
72
+ return current ? null : {
73
+ index: readIndex(state)
74
+ };
75
+ });
76
+ }, [enabled]);
77
+ // A tap outside the chart unpins.
78
+ useEffect(function () {
79
+ if (!pinned) return undefined;
80
+ var onDown = function onDown(e) {
81
+ if (wrapperRef.current && !wrapperRef.current.contains(e.target)) setPinned(null);
82
+ };
83
+ document.addEventListener("pointerdown", onDown);
84
+ return function () {
85
+ return document.removeEventListener("pointerdown", onDown);
86
+ };
87
+ }, [pinned]);
88
+ var tooltipProps = pinned ? _objectSpread2({
89
+ active: true
90
+ }, pinned.index !== undefined ? {
91
+ defaultIndex: pinned.index
92
+ } : {}) : {};
93
+ return {
94
+ pinned: Boolean(pinned),
95
+ wrapperProps: {
96
+ ref: wrapperRef,
97
+ onPointerDownCapture: onPointerDownCapture,
98
+ "data-tooltip-pinned": pinned ? "true" : undefined
99
+ },
100
+ onChartClick: toggle,
101
+ tooltipProps: tooltipProps
102
+ };
103
+ }
104
+
105
+ export { tickGapFor, useElementWidth, usePinnedTooltip, yAxisWidthFor };
@@ -1,11 +1,18 @@
1
1
  'use client';
2
- import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
- import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { objectWithoutProperties as _objectWithoutProperties, defineProperty as _defineProperty, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
4
  import { forwardRef } from 'react';
5
5
  import { cn } from '../../utils/cn.js';
6
+ import { TOUCH_TARGET, PRESS_FEEDBACK } from '../../utils/touchTarget.js';
6
7
  import { Loader2 } from 'lucide-react';
7
8
 
8
9
  var _excluded = ["className", "variant", "size", "disabled", "loading", "children", "leftIcon", "rightIcon", "fullWidth", "as", "onClick"];
10
+ // Square, icon-only sizes. Pair with an `aria-label` (there is no visible text).
11
+ var ICON_SIZES = {
12
+ 'icon-sm': 'h-8 w-8 p-0',
13
+ icon: 'h-10 w-10 p-0',
14
+ 'icon-lg': 'h-12 w-12 p-0'
15
+ };
9
16
  var Button = /*#__PURE__*/forwardRef(function (_ref, ref) {
10
17
  var className = _ref.className,
11
18
  _ref$variant = _ref.variant,
@@ -26,26 +33,37 @@ var Button = /*#__PURE__*/forwardRef(function (_ref, ref) {
26
33
  var Component = as || (props.href !== undefined ? 'a' : 'button');
27
34
  var isNativeButton = Component === 'button';
28
35
  var isDisabled = disabled || loading;
29
- var baseClasses = cn('inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:pointer-events-none', {
30
- // Variants
31
- 'bg-primary-600 text-white hover:bg-primary-700 focus-visible:ring-primary-500': variant === 'primary',
32
- 'bg-secondary-100 text-secondary-900 hover:bg-secondary-200 focus-visible:ring-secondary-500': variant === 'secondary',
33
- 'bg-transparent border border-gray-300 hover:bg-gray-50 focus-visible:ring-primary-500 dark:border-gray-600 dark:text-gray-100 dark:hover:bg-gray-800 dark:focus-visible:ring-offset-gray-900': variant === 'outline',
34
- 'bg-transparent text-primary-600 hover:bg-primary-50 focus-visible:ring-primary-500': variant === 'ghost',
35
- 'bg-error-600 text-white hover:bg-error-700 focus-visible:ring-error-500': variant === 'destructive',
36
- 'bg-success-600 text-white hover:bg-success-700 focus-visible:ring-success-500': variant === 'success',
37
- 'bg-warning-600 text-white hover:bg-warning-700 focus-visible:ring-warning-500': variant === 'warning',
36
+ var isIconSize = Boolean(ICON_SIZES[size]);
37
+ var baseClasses = cn('relative inline-flex items-center justify-center rounded-md font-medium',
38
+ // Press shrink + an explicit transition for colours and the shrink;
39
+ // both are off under prefers-reduced-motion.
40
+ PRESS_FEEDBACK, 'transition duration-fast ease-standard motion-reduce:transition-none', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-900', 'disabled:opacity-50 disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:pointer-events-none', _defineProperty(_defineProperty({
41
+ // Variants (each with dark-mode colours).
42
+ 'bg-primary-600 text-white hover:bg-primary-700 focus-visible:ring-primary-500 dark:hover:bg-primary-500': variant === 'primary',
43
+ 'bg-secondary-100 text-secondary-900 hover:bg-secondary-200 focus-visible:ring-secondary-500 dark:bg-secondary-800 dark:text-secondary-100 dark:hover:bg-secondary-700': variant === 'secondary',
44
+ 'bg-transparent border border-gray-300 hover:bg-gray-50 focus-visible:ring-primary-500 dark:border-gray-600 dark:text-gray-100 dark:hover:bg-gray-800': variant === 'outline',
45
+ 'bg-transparent text-primary-600 hover:bg-primary-50 focus-visible:ring-primary-500 dark:text-primary-300 dark:hover:bg-primary-900/40': variant === 'ghost',
46
+ 'bg-error-600 text-white hover:bg-error-700 focus-visible:ring-error-500 dark:hover:bg-error-500': variant === 'destructive',
47
+ 'bg-success-600 text-white hover:bg-success-700 focus-visible:ring-success-500 dark:hover:bg-success-500': variant === 'success',
48
+ 'bg-warning-600 text-white hover:bg-warning-700 focus-visible:ring-warning-500 dark:hover:bg-warning-500': variant === 'warning',
38
49
  // Sizes — every value of the shared `Size` type gets a real height.
39
50
  'h-7 px-2 text-xs': size === 'xs',
40
51
  'h-8 px-3 text-xs': size === 'sm',
41
52
  'h-10 px-4 text-sm': size === 'md',
42
53
  'h-12 px-6 text-base': size === 'lg',
43
54
  'h-14 px-8 text-lg': size === 'xl',
44
- 'h-16 px-10 text-xl': size === '2xl',
45
- // Full width
46
- 'w-full': fullWidth
47
- }, className);
48
- return jsxs(Component, _objectSpread2(_objectSpread2(_objectSpread2({
55
+ 'h-16 px-10 text-xl': size === '2xl'
56
+ }, TOUCH_TARGET, size === 'xs' || size === 'sm' || size === 'icon-sm' || size === 'icon'), 'w-full', fullWidth), ICON_SIZES[size], className);
57
+ var content = jsxs(Fragment, {
58
+ children: [leftIcon && jsx("span", {
59
+ className: isIconSize ? undefined : 'mr-2',
60
+ children: leftIcon
61
+ }), children, rightIcon && jsx("span", {
62
+ className: isIconSize ? undefined : 'ml-2',
63
+ children: rightIcon
64
+ })]
65
+ });
66
+ return jsx(Component, _objectSpread2(_objectSpread2(_objectSpread2({
49
67
  ref: ref,
50
68
  className: baseClasses
51
69
  }, isNativeButton ? {
@@ -56,19 +74,25 @@ var Button = /*#__PURE__*/forwardRef(function (_ref, ref) {
56
74
  'aria-disabled': true,
57
75
  tabIndex: -1
58
76
  }), {}, {
77
+ "aria-busy": loading ? true : undefined,
59
78
  onClick: !isNativeButton && isDisabled ? function (e) {
60
79
  return e.preventDefault();
61
80
  } : onClick
62
81
  }, props), {}, {
63
- children: [loading && jsx(Loader2, {
64
- className: "mr-2 h-4 w-4 animate-spin"
65
- }), !loading && leftIcon && jsx("span", {
66
- className: "mr-2",
67
- children: leftIcon
68
- }), children, !loading && rightIcon && jsx("span", {
69
- className: "ml-2",
70
- children: rightIcon
71
- })]
82
+ children: loading ? jsxs(Fragment, {
83
+ children: [jsx("span", {
84
+ className: "inline-flex items-center opacity-0",
85
+ "data-slot": "label",
86
+ children: content
87
+ }), jsx("span", {
88
+ className: "absolute inset-0 flex items-center justify-center",
89
+ "data-slot": "spinner",
90
+ "aria-hidden": "true",
91
+ children: jsx(Loader2, {
92
+ className: "h-4 w-4 animate-spin motion-reduce:animate-none"
93
+ })
94
+ })]
95
+ }) : content
72
96
  }));
73
97
  });
74
98
  Button.displayName = 'Button';