@dreamtree-org/twreact-ui 1.3.10 → 2.0.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 (230) hide show
  1. package/README.md +70 -6
  2. package/ai-skills/dreamtree-ui.md +58 -15
  3. package/codemods/v2.cjs +198 -0
  4. package/dist/ai-schema.json +745 -53
  5. package/dist/charts/index.js +195 -66
  6. package/dist/components/blocks/AppShell.d.ts.map +1 -1
  7. package/dist/components/blocks/BottomActionBar.d.ts +6 -0
  8. package/dist/components/blocks/BottomActionBar.d.ts.map +1 -0
  9. package/dist/components/blocks/ConfirmDialog.d.ts.map +1 -1
  10. package/dist/components/blocks/PageHeader.d.ts.map +1 -1
  11. package/dist/components/charts/CartesianChart.d.ts.map +1 -1
  12. package/dist/components/charts/ChartFrame.d.ts.map +1 -1
  13. package/dist/components/charts/useChartLayout.d.ts +25 -0
  14. package/dist/components/charts/useChartLayout.d.ts.map +1 -0
  15. package/dist/components/core/Button.d.ts.map +1 -1
  16. package/dist/components/core/Checkbox.d.ts.map +1 -1
  17. package/dist/components/core/ColorPicker.d.ts.map +1 -1
  18. package/dist/components/core/DatePicker.d.ts.map +1 -1
  19. package/dist/components/core/DateRangePicker.d.ts.map +1 -1
  20. package/dist/components/core/Form.d.ts.map +1 -1
  21. package/dist/components/core/Input.d.ts.map +1 -1
  22. package/dist/components/core/Loader.d.ts.map +1 -1
  23. package/dist/components/core/LocationPicker.d.ts.map +1 -1
  24. package/dist/components/core/Popover.d.ts.map +1 -1
  25. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  26. package/dist/components/core/Radio.d.ts.map +1 -1
  27. package/dist/components/core/Rate.d.ts.map +1 -1
  28. package/dist/components/core/RoundedTag.d.ts.map +1 -1
  29. package/dist/components/core/SearchField.d.ts +9 -0
  30. package/dist/components/core/SearchField.d.ts.map +1 -0
  31. package/dist/components/core/SegmentedControl.d.ts +8 -0
  32. package/dist/components/core/SegmentedControl.d.ts.map +1 -0
  33. package/dist/components/core/Select.d.ts.map +1 -1
  34. package/dist/components/core/Skeleton.d.ts.map +1 -1
  35. package/dist/components/core/Slider.d.ts.map +1 -1
  36. package/dist/components/core/SpeechToText.d.ts.map +1 -1
  37. package/dist/components/core/SwipeableListItem.d.ts +4 -0
  38. package/dist/components/core/SwipeableListItem.d.ts.map +1 -0
  39. package/dist/components/core/SwipeableListItemGesture.d.ts +58 -0
  40. package/dist/components/core/SwipeableListItemGesture.d.ts.map +1 -0
  41. package/dist/components/core/Switch.d.ts.map +1 -1
  42. package/dist/components/core/Table/ActionMenu.d.ts +10 -3
  43. package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
  44. package/dist/components/core/Table/MobileCard.d.ts +10 -1
  45. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  46. package/dist/components/core/Table/MobileFilters.d.ts +8 -2
  47. package/dist/components/core/Table/MobileFilters.d.ts.map +1 -1
  48. package/dist/components/core/Table/Table.d.ts.map +1 -1
  49. package/dist/components/core/Table/TableRow.d.ts +2 -1
  50. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  51. package/dist/components/core/Tabs.d.ts +5 -8
  52. package/dist/components/core/Tabs.d.ts.map +1 -1
  53. package/dist/components/core/Textarea.d.ts.map +1 -1
  54. package/dist/components/core/ThreeDotPopover.d.ts +10 -22
  55. package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
  56. package/dist/components/core/Tooltip.d.ts +2 -1
  57. package/dist/components/core/Tooltip.d.ts.map +1 -1
  58. package/dist/components/core/internal/Calendar.d.ts +77 -0
  59. package/dist/components/core/internal/Calendar.d.ts.map +1 -0
  60. package/dist/components/core/menu/ActionMenuSurface.d.ts +42 -0
  61. package/dist/components/core/menu/ActionMenuSurface.d.ts.map +1 -0
  62. package/dist/components/core/menu/ActionSheetMenu.d.ts +17 -0
  63. package/dist/components/core/menu/ActionSheetMenu.d.ts.map +1 -0
  64. package/dist/components/core/menu/MenuPopover.d.ts +21 -0
  65. package/dist/components/core/menu/MenuPopover.d.ts.map +1 -0
  66. package/dist/components/core/menu/menuItems.d.ts +21 -0
  67. package/dist/components/core/menu/menuItems.d.ts.map +1 -0
  68. package/dist/components/core/menu/menuKeyboard.d.ts +16 -0
  69. package/dist/components/core/menu/menuKeyboard.d.ts.map +1 -0
  70. package/dist/components/feedback/ActionSheet.d.ts +4 -0
  71. package/dist/components/feedback/ActionSheet.d.ts.map +1 -0
  72. package/dist/components/feedback/Alert.d.ts.map +1 -1
  73. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  74. package/dist/components/feedback/Drawer.d.ts.map +1 -1
  75. package/dist/components/feedback/Sheet.d.ts +4 -0
  76. package/dist/components/feedback/Sheet.d.ts.map +1 -0
  77. package/dist/components/feedback/Toast.d.ts +4 -3
  78. package/dist/components/feedback/Toast.d.ts.map +1 -1
  79. package/dist/components/feedback/ToastItem.d.ts +47 -0
  80. package/dist/components/feedback/ToastItem.d.ts.map +1 -0
  81. package/dist/components/feedback/ToastStack.d.ts +20 -0
  82. package/dist/components/feedback/ToastStack.d.ts.map +1 -0
  83. package/dist/components/feedback/ToastSwipe.d.ts +22 -0
  84. package/dist/components/feedback/ToastSwipe.d.ts.map +1 -0
  85. package/dist/components/feedback/Tour.d.ts.map +1 -1
  86. package/dist/components/feedback/sheetCore.d.ts +30 -0
  87. package/dist/components/feedback/sheetCore.d.ts.map +1 -0
  88. package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
  89. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  90. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  91. package/dist/components/navigation/Sidebar.d.ts +6 -0
  92. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  93. package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -1
  94. package/dist/components/rich-text/RichTextToolbar.d.ts +6 -2
  95. package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -1
  96. package/dist/components/utility/Avatar.d.ts +8 -0
  97. package/dist/components/utility/Avatar.d.ts.map +1 -1
  98. package/dist/components/utility/AvatarGroup.d.ts +4 -0
  99. package/dist/components/utility/AvatarGroup.d.ts.map +1 -0
  100. package/dist/components/utility/Badge.d.ts.map +1 -1
  101. package/dist/components/utility/Card.d.ts.map +1 -1
  102. package/dist/components/utility/Carousel.d.ts.map +1 -1
  103. package/dist/components/utility/FileUpload.d.ts.map +1 -1
  104. package/dist/components/utility/Pagination.d.ts.map +1 -1
  105. package/dist/components/utility/PullToRefresh.d.ts +5 -0
  106. package/dist/components/utility/PullToRefresh.d.ts.map +1 -0
  107. package/dist/components/utility/Sortable.d.ts.map +1 -1
  108. package/dist/components/utility/Stepper.d.ts.map +1 -1
  109. package/dist/esm/components/blocks/AppShell.js +97 -90
  110. package/dist/esm/components/blocks/BottomActionBar.js +132 -0
  111. package/dist/esm/components/blocks/ConfirmDialog.js +40 -4
  112. package/dist/esm/components/blocks/EmptyState.js +1 -1
  113. package/dist/esm/components/blocks/ErrorState.js +1 -1
  114. package/dist/esm/components/blocks/LoadingState.js +4 -4
  115. package/dist/esm/components/blocks/PageHeader.js +16 -3
  116. package/dist/esm/components/blocks/StatCard.js +6 -6
  117. package/dist/esm/components/blocks/StatusPill.js +5 -8
  118. package/dist/esm/components/charts/CartesianChart.js +85 -62
  119. package/dist/esm/components/charts/ChartFrame.js +12 -5
  120. package/dist/esm/components/charts/useChartLayout.js +105 -0
  121. package/dist/esm/components/core/Button.js +49 -25
  122. package/dist/esm/components/core/Checkbox.js +72 -57
  123. package/dist/esm/components/core/ColorPicker.js +31 -42
  124. package/dist/esm/components/core/DatePicker.js +117 -304
  125. package/dist/esm/components/core/DateRangePicker.js +260 -308
  126. package/dist/esm/components/core/Form.js +11 -2
  127. package/dist/esm/components/core/Input.js +100 -38
  128. package/dist/esm/components/core/Loader.js +30 -44
  129. package/dist/esm/components/core/LocationPicker.js +82 -16
  130. package/dist/esm/components/core/Popover.js +59 -48
  131. package/dist/esm/components/core/ProgressBar.js +40 -72
  132. package/dist/esm/components/core/Radio.js +10 -12
  133. package/dist/esm/components/core/Rate.js +77 -14
  134. package/dist/esm/components/core/RoundedTag.js +5 -5
  135. package/dist/esm/components/core/SearchField.js +311 -0
  136. package/dist/esm/components/core/SegmentedControl.js +189 -0
  137. package/dist/esm/components/core/Select.js +185 -190
  138. package/dist/esm/components/core/Skeleton.js +13 -14
  139. package/dist/esm/components/core/Slider.js +24 -6
  140. package/dist/esm/components/core/SpeechToText.js +68 -16
  141. package/dist/esm/components/core/SwipeableListItem.js +286 -0
  142. package/dist/esm/components/core/SwipeableListItemGesture.js +219 -0
  143. package/dist/esm/components/core/Switch.js +98 -28
  144. package/dist/esm/components/core/Table/ActionMenu.js +45 -231
  145. package/dist/esm/components/core/Table/ColumnMenu.js +1 -1
  146. package/dist/esm/components/core/Table/MobileCard.js +66 -16
  147. package/dist/esm/components/core/Table/MobileFilters.js +181 -10
  148. package/dist/esm/components/core/Table/Table.js +149 -102
  149. package/dist/esm/components/core/Table/TableRow.js +10 -2
  150. package/dist/esm/components/core/Tabs.js +186 -39
  151. package/dist/esm/components/core/Textarea.js +10 -2
  152. package/dist/esm/components/core/ThreeDotPopover.js +93 -99
  153. package/dist/esm/components/core/Tooltip.js +138 -145
  154. package/dist/esm/components/core/internal/Calendar.js +381 -0
  155. package/dist/esm/components/core/menu/ActionMenuSurface.js +110 -0
  156. package/dist/esm/components/core/menu/ActionSheetMenu.js +140 -0
  157. package/dist/esm/components/core/menu/MenuPopover.js +177 -0
  158. package/dist/esm/components/core/menu/menuItems.js +61 -0
  159. package/dist/esm/components/core/menu/menuKeyboard.js +54 -0
  160. package/dist/esm/components/feedback/ActionSheet.js +55 -0
  161. package/dist/esm/components/feedback/Alert.js +63 -53
  162. package/dist/esm/components/feedback/Dialog.js +141 -53
  163. package/dist/esm/components/feedback/Drawer.js +130 -132
  164. package/dist/esm/components/feedback/Sheet.js +125 -0
  165. package/dist/esm/components/feedback/Toast.js +21 -291
  166. package/dist/esm/components/feedback/ToastItem.js +348 -0
  167. package/dist/esm/components/feedback/ToastStack.js +130 -0
  168. package/dist/esm/components/feedback/ToastSwipe.js +52 -0
  169. package/dist/esm/components/feedback/Tour.js +107 -30
  170. package/dist/esm/components/feedback/sheetCore.js +494 -0
  171. package/dist/esm/components/navigation/Breadcrumbs.js +97 -35
  172. package/dist/esm/components/navigation/Dropdown.js +1 -1
  173. package/dist/esm/components/navigation/FootNav.js +102 -13
  174. package/dist/esm/components/navigation/Navbar.js +172 -37
  175. package/dist/esm/components/navigation/Sidebar.js +263 -111
  176. package/dist/esm/components/rich-text/RichTextEditor.js +9 -3
  177. package/dist/esm/components/rich-text/RichTextToolbar.js +29 -9
  178. package/dist/esm/components/utility/Avatar.js +14 -12
  179. package/dist/esm/components/utility/AvatarGroup.js +56 -0
  180. package/dist/esm/components/utility/Badge.js +43 -23
  181. package/dist/esm/components/utility/Card.js +32 -8
  182. package/dist/esm/components/utility/Carousel.js +139 -29
  183. package/dist/esm/components/utility/FileUpload.js +106 -31
  184. package/dist/esm/components/utility/Pagination.js +31 -13
  185. package/dist/esm/components/utility/Portal.js +31 -0
  186. package/dist/esm/components/utility/PullToRefresh.js +229 -0
  187. package/dist/esm/components/utility/Sortable.js +6 -2
  188. package/dist/esm/components/utility/Stepper.js +110 -47
  189. package/dist/esm/hooks/useFloatingPosition.js +82 -0
  190. package/dist/esm/hooks/useHaptics.js +65 -0
  191. package/dist/esm/hooks/usePresence.js +58 -0
  192. package/dist/esm/hooks/usePresentation.js +21 -0
  193. package/dist/esm/hooks/useSheetDrag.js +220 -0
  194. package/dist/esm/hooks/useSliderValues.js +8 -2
  195. package/dist/esm/hooks/useSortable.js +107 -5
  196. package/dist/esm/index.js +14 -2
  197. package/dist/esm/utils/position.js +10 -63
  198. package/dist/esm/utils/touchTarget.js +4 -1
  199. package/dist/hooks/useFloatingPosition.d.ts +8 -4
  200. package/dist/hooks/useFloatingPosition.d.ts.map +1 -1
  201. package/dist/hooks/useHaptics.d.ts +19 -0
  202. package/dist/hooks/useHaptics.d.ts.map +1 -0
  203. package/dist/hooks/useSheetDrag.d.ts +31 -0
  204. package/dist/hooks/useSheetDrag.d.ts.map +1 -0
  205. package/dist/hooks/useSliderValues.d.ts +6 -2
  206. package/dist/hooks/useSliderValues.d.ts.map +1 -1
  207. package/dist/hooks/useSortable.d.ts +11 -1
  208. package/dist/hooks/useSortable.d.ts.map +1 -1
  209. package/dist/index.css +1 -1
  210. package/dist/index.d.ts +11 -2
  211. package/dist/index.esm.css +1 -1
  212. package/dist/index.esm.js +10645 -3842
  213. package/dist/index.js +10657 -3845
  214. package/dist/rich-text/index.js +41 -11
  215. package/dist/types/blocks.d.ts +32 -2
  216. package/dist/types/blocks.d.ts.map +1 -1
  217. package/dist/types/charts.d.ts +3 -1
  218. package/dist/types/charts.d.ts.map +1 -1
  219. package/dist/types/index.d.ts +409 -26
  220. package/dist/types/index.d.ts.map +1 -1
  221. package/dist/types/rich-text.d.ts +5 -0
  222. package/dist/types/rich-text.d.ts.map +1 -1
  223. package/dist/utils/position.d.ts +0 -15
  224. package/dist/utils/position.d.ts.map +1 -1
  225. package/doc/README.md +16 -0
  226. package/mcp/catalog.snapshot.json +1540 -407
  227. package/package.json +7 -2
  228. package/dist/esm/hooks/useSwipeToClose.js +0 -66
  229. package/dist/hooks/useSwipeToClose.d.ts +0 -24
  230. package/dist/hooks/useSwipeToClose.d.ts.map +0 -1
@@ -1,11 +1,11 @@
1
1
  'use client';
2
- import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
- import { forwardRef, useId, useRef, useMemo } from 'react';
4
+ import { forwardRef, useId, useRef, useMemo, useState } from 'react';
5
5
  import { cn } from '../../utils/cn.js';
6
6
  import { useSliderValues, useSliderPointer, toPercent, keyToValue } from '../../hooks/useSliderValues.js';
7
7
 
8
- var _excluded = ["value", "defaultValue", "onChange", "onChangeEnd", "min", "max", "step", "largeStep", "disabled", "label", "showValue", "formatValue", "thumbLabels", "name", "className", "aria-label"];
8
+ var _excluded = ["value", "defaultValue", "onChange", "onChangeEnd", "min", "max", "step", "largeStep", "disabled", "label", "showValue", "showBubble", "formatValue", "thumbLabels", "name", "className", "aria-label"];
9
9
  var DEFAULT_THUMB_LABELS = ["Minimum", "Maximum"];
10
10
  var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
11
11
  var value = _ref.value,
@@ -24,6 +24,8 @@ var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
24
24
  label = _ref.label,
25
25
  _ref$showValue = _ref.showValue,
26
26
  showValue = _ref$showValue === void 0 ? false : _ref$showValue,
27
+ _ref$showBubble = _ref.showBubble,
28
+ showBubble = _ref$showBubble === void 0 ? true : _ref$showBubble,
27
29
  _ref$formatValue = _ref.formatValue,
28
30
  formatValue = _ref$formatValue === void 0 ? String : _ref$formatValue,
29
31
  _ref$thumbLabels = _ref.thumbLabels,
@@ -52,12 +54,18 @@ var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
52
54
  values = _useSliderValues.values,
53
55
  isRange = _useSliderValues.isRange,
54
56
  setThumb = _useSliderValues.setThumb;
57
+ // Index of the thumb being dragged (drives the value bubble), else null.
58
+ var _useState = useState(null),
59
+ _useState2 = _slicedToArray(_useState, 2),
60
+ dragging = _useState2[0],
61
+ setDragging = _useState2[1];
55
62
  var pointer = useSliderPointer({
56
63
  trackRef: trackRef,
57
64
  values: values,
58
65
  setThumb: setThumb,
59
66
  bounds: bounds,
60
- disabled: disabled
67
+ disabled: disabled,
68
+ onActiveChange: setDragging
61
69
  });
62
70
  var handleKeyDown = function handleKeyDown(index) {
63
71
  return function (e) {
@@ -90,7 +98,9 @@ var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
90
98
  })]
91
99
  }), jsxs("div", _objectSpread2(_objectSpread2({
92
100
  ref: trackRef,
93
- className: cn("relative flex h-5 touch-none select-none items-center", disabled ? "cursor-not-allowed" : "cursor-pointer")
101
+ className: cn(
102
+ // 44px tall row on coarse pointers so the whole strip is easy to grab.
103
+ "relative flex h-5 touch-none select-none items-center [@media(pointer:coarse)]:h-11", disabled ? "cursor-not-allowed" : "cursor-pointer")
94
104
  }, pointer), {}, {
95
105
  children: [jsx("div", {
96
106
  className: "h-1.5 w-full rounded-full bg-gray-200 dark:bg-gray-700"
@@ -117,7 +127,15 @@ var Slider = /*#__PURE__*/forwardRef(function (_ref, ref) {
117
127
  style: {
118
128
  left: "".concat(toPercent(v, min, max), "%")
119
129
  },
120
- className: cn("absolute h-4 w-4 -translate-x-1/2 rounded-full border-2 border-primary-600 bg-white shadow", "transition-shadow motion-reduce:transition-none", "focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500", "dark:border-primary-500 dark:bg-gray-900 dark:focus:ring-offset-gray-900")
130
+ className: cn("absolute h-4 w-4 -translate-x-1/2 rounded-full border-2 border-primary-600 bg-surface shadow", "transition-shadow duration-fast motion-reduce:transition-none", "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary-500", "dark:border-primary-500 dark:focus-visible:ring-offset-gray-900",
131
+ // Grow the hit area to 44px on touch without changing the visual size.
132
+ "before:absolute before:left-1/2 before:top-1/2 before:-translate-x-1/2 before:-translate-y-1/2", "[@media(pointer:coarse)]:before:h-11 [@media(pointer:coarse)]:before:w-11 before:content-['']"),
133
+ children: showBubble && dragging === i && jsx("span", {
134
+ "aria-hidden": "true",
135
+ "data-slider-bubble": "",
136
+ className: cn("pointer-events-none absolute -top-9 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md border border-line", "bg-surface px-2 py-1 text-xs tabular-nums text-foreground shadow-sm", "animate-scale-in motion-reduce:animate-none"),
137
+ children: formatValue(v)
138
+ })
121
139
  }, i);
122
140
  })]
123
141
  })), name && values.map(function (v, i) {
@@ -4,8 +4,21 @@ import { jsxs, jsx } from 'react/jsx-runtime';
4
4
  import { forwardRef, useRef, useState, useEffect, useCallback, useImperativeHandle } from 'react';
5
5
  import { MicOff, Mic } from 'lucide-react';
6
6
  import { cn } from '../../utils/cn.js';
7
+ import { PRESS_FEEDBACK } from '../../utils/touchTarget.js';
7
8
 
8
9
  var _excluded = ["lang", "continuous", "interimResults", "onSpeechComplete", "onSpeaking", "onError", "onStart", "onStop", "renderButton", "autoStart", "disabled", "resetOnStart", "className"];
10
+ // Level bars (DTUI-42). There is no audio-level API without getUserMedia, so the
11
+ // bars show *whether* speech is being heard (speechstart / results), not volume.
12
+ var LEVEL_BARS = [{
13
+ height: "h-2",
14
+ delay: "[animation-delay:0ms]"
15
+ }, {
16
+ height: "h-3.5",
17
+ delay: "[animation-delay:150ms]"
18
+ }, {
19
+ height: "h-2.5",
20
+ delay: "[animation-delay:300ms]"
21
+ }];
9
22
  var isProbablyMobile = function isProbablyMobile() {
10
23
  if (typeof navigator === "undefined") return false;
11
24
  return /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
@@ -48,14 +61,19 @@ var SpeechToText = /*#__PURE__*/forwardRef(function (_ref, ref) {
48
61
  _useState2 = _slicedToArray(_useState, 2),
49
62
  _isListening = _useState2[0],
50
63
  setIsListening = _useState2[1];
51
- var _useState3 = useState(true),
64
+ // True while the engine reports speech (speechstart → speechend, or results).
65
+ var _useState3 = useState(false),
52
66
  _useState4 = _slicedToArray(_useState3, 2),
53
- _isSupported = _useState4[0],
54
- setIsSupported = _useState4[1];
55
- var _useState5 = useState(null),
67
+ isHearing = _useState4[0],
68
+ setIsHearing = _useState4[1];
69
+ var _useState5 = useState(true),
56
70
  _useState6 = _slicedToArray(_useState5, 2),
57
- error = _useState6[0],
58
- setError = _useState6[1];
71
+ _isSupported = _useState6[0],
72
+ setIsSupported = _useState6[1];
73
+ var _useState7 = useState(null),
74
+ _useState8 = _slicedToArray(_useState7, 2),
75
+ error = _useState8[0],
76
+ setError = _useState8[1];
59
77
  useEffect(function () {
60
78
  var hasSpeechRecognition = typeof window !== "undefined" && ("SpeechRecognition" in window || "webkitSpeechRecognition" in window);
61
79
  setIsSupported(hasSpeechRecognition);
@@ -76,6 +94,14 @@ var SpeechToText = /*#__PURE__*/forwardRef(function (_ref, ref) {
76
94
  recognition.continuous = isProbablyMobile() ? false : continuous;
77
95
  recognition.interimResults = interimResults;
78
96
  recognition.lang = lang;
97
+ recognition.onspeechstart = function () {
98
+ if (!isMountedRef.current) return;
99
+ setIsHearing(true);
100
+ };
101
+ recognition.onspeechend = function () {
102
+ if (!isMountedRef.current) return;
103
+ setIsHearing(false);
104
+ };
79
105
  recognition.onstart = function () {
80
106
  if (!isMountedRef.current) return;
81
107
  setIsListening(true);
@@ -97,6 +123,7 @@ var SpeechToText = /*#__PURE__*/forwardRef(function (_ref, ref) {
97
123
  interim += text;
98
124
  }
99
125
  }
126
+ if (interim || finalChunk) setIsHearing(true);
100
127
  if (interim) onSpeaking(interim.trim());
101
128
  if (finalChunk) onSpeechComplete(finalChunk.trim());
102
129
  };
@@ -107,11 +134,13 @@ var SpeechToText = /*#__PURE__*/forwardRef(function (_ref, ref) {
107
134
  var err = new Error((event === null || event === void 0 ? void 0 : event.error) || "Speech recognition error");
108
135
  setError(err);
109
136
  setIsListening(false);
137
+ setIsHearing(false);
110
138
  onError(err);
111
139
  };
112
140
  recognition.onend = function () {
113
141
  if (!isMountedRef.current) return;
114
142
  setIsListening(false);
143
+ setIsHearing(false);
115
144
  onStop();
116
145
  };
117
146
  recognitionRef.current = recognition;
@@ -192,6 +221,7 @@ var SpeechToText = /*#__PURE__*/forwardRef(function (_ref, ref) {
192
221
  // eslint-disable-next-line react-hooks/refs
193
222
  return renderButton({
194
223
  isListening: _isListening,
224
+ isHearing: isHearing,
195
225
  isSupported: _isSupported,
196
226
  error: error,
197
227
  start: startListening,
@@ -207,18 +237,40 @@ var SpeechToText = /*#__PURE__*/forwardRef(function (_ref, ref) {
207
237
  "aria-label": _isListening ? "Stop listening" : "Start listening",
208
238
  onClick: toggleListening,
209
239
  disabled: isDisabled,
210
- className: cn("inline-flex items-center gap-2 rounded-md px-4 h-10 text-sm font-medium", "border border-gray-300 bg-transparent transition-colors", "hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500", "disabled:opacity-50 disabled:pointer-events-none", {
211
- "text-error-600 border-error-600": _isListening,
212
- "text-gray-900": !_isListening
240
+ "data-listening": _isListening || undefined,
241
+ "data-hearing": _isListening && isHearing || undefined,
242
+ className: cn("inline-flex items-center gap-2 rounded-md px-4 h-10 text-sm font-medium", "[@media(pointer:coarse)]:min-h-11", "border border-gray-300 bg-transparent transition-colors duration-fast motion-reduce:transition-none", "hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800", "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary-500 dark:focus-visible:ring-offset-gray-900", "disabled:opacity-50 disabled:pointer-events-none", PRESS_FEEDBACK,
243
+ // PRESS_FEEDBACK sets transition-transform; keep the colour transition too.
244
+ "transition-[color,background-color,border-color,transform]", {
245
+ "text-error-600 border-error-600 dark:text-error-400 dark:border-error-400": _isListening,
246
+ "text-gray-900 dark:text-gray-100": !_isListening
213
247
  }, className)
214
248
  }, rest), {}, {
215
- children: [_isListening ? jsx(MicOff, {
216
- className: "h-4 w-4",
217
- "aria-hidden": "true"
218
- }) : jsx(Mic, {
219
- className: "h-4 w-4",
220
- "aria-hidden": "true"
221
- }), _isListening ? "Stop" : "Start"]
249
+ children: [jsxs("span", {
250
+ className: "relative inline-flex h-4 w-4 items-center justify-center",
251
+ "aria-hidden": "true",
252
+ children: [_isListening &&
253
+ // Listening pulse; a static ring replaces it under reduced motion.
254
+ jsx("span", {
255
+ "data-testid": "stt-pulse",
256
+ className: "absolute -inset-1.5 rounded-full bg-error-500/30 animate-ping motion-reduce:animate-none motion-reduce:bg-transparent motion-reduce:ring-2 motion-reduce:ring-error-500/60"
257
+ }), _isListening ? jsx(MicOff, {
258
+ className: "relative h-4 w-4",
259
+ "aria-hidden": "true"
260
+ }) : jsx(Mic, {
261
+ className: "relative h-4 w-4",
262
+ "aria-hidden": "true"
263
+ })]
264
+ }), _isListening ? "Stop" : "Start", _isListening && jsx("span", {
265
+ className: "inline-flex h-3.5 items-end gap-0.5",
266
+ "aria-hidden": "true",
267
+ "data-testid": "stt-level",
268
+ children: LEVEL_BARS.map(function (bar, i) {
269
+ return jsx("span", {
270
+ className: cn("w-0.5 rounded-full transition-colors duration-base motion-reduce:transition-none", isHearing ? cn("bg-current animate-pulse motion-reduce:animate-none", bar.height, bar.delay) : "h-1 bg-current opacity-40")
271
+ }, i);
272
+ })
273
+ })]
222
274
  }));
223
275
  });
224
276
  SpeechToText.displayName = "SpeechToText";
@@ -0,0 +1,286 @@
1
+ 'use client';
2
+ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, typeof as _typeof, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+ import React, { useMemo, useRef, useState, useCallback } from 'react';
5
+ import { MoreHorizontal } from 'lucide-react';
6
+ import { cn } from '../../utils/cn.js';
7
+ import { setRefs } from '../../utils/position.js';
8
+ import { useControllableState } from '../../hooks/useControllableState.js';
9
+ import { useClickOutside } from '../../hooks/useClickOutside.js';
10
+ import ActionMenuSurface from './menu/ActionMenuSurface.js';
11
+ import { renderIcon } from './menu/menuItems.js';
12
+ import { useSwipeGesture, restingOffset } from './SwipeableListItemGesture.js';
13
+
14
+ var _excluded = ["as", "children", "leadingActions", "trailingActions", "fullSwipe", "fullSwipeThreshold", "actionWidth", "open", "defaultOpen", "onOpenChange", "disabled", "moreActions", "moreActionsLabel", "menuPresentation", "contentClassName", "className", "onKeyDown"];
15
+ // The iOS Mail / Gmail row: swipe horizontally to reveal actions, swipe all
16
+ // the way to commit the first one. Every action is also reachable without a
17
+ // gesture through the "More actions" button (a menu, or an action sheet on
18
+ // phones).
19
+ var TONE_CLASSES = {
20
+ "default": "bg-secondary-600 text-secondary-50",
21
+ primary: "bg-primary-600 text-primary-50",
22
+ secondary: "bg-secondary-600 text-secondary-50",
23
+ success: "bg-success-600 text-success-50",
24
+ warning: "bg-warning-600 text-warning-50",
25
+ info: "bg-info-600 text-info-50",
26
+ error: "bg-error-600 text-error-50",
27
+ destructive: "bg-error-600 text-error-50"
28
+ };
29
+ var MOTION = "duration-base ease-standard motion-reduce:transition-none";
30
+ var toneClass = function toneClass(tone) {
31
+ return TONE_CLASSES[tone] || TONE_CLASSES["default"];
32
+ };
33
+ var isMenuDestructive = function isMenuDestructive(tone) {
34
+ return tone === "destructive" || tone === "error";
35
+ };
36
+ function ActionPanel(_ref) {
37
+ var side = _ref.side,
38
+ actions = _ref.actions,
39
+ width = _ref.width,
40
+ open = _ref.open,
41
+ armed = _ref.armed,
42
+ dragging = _ref.dragging,
43
+ onSelect = _ref.onSelect;
44
+ // The first action sits at the outer edge, so trailing actions render reversed.
45
+ var ordered = side === "trailing" ? _toConsumableArray(actions).reverse() : actions;
46
+ var first = actions[0];
47
+ return jsx("div", {
48
+ "data-swipe-actions": side,
49
+ "aria-hidden": open ? undefined : true,
50
+ className: cn("absolute inset-y-0 flex overflow-hidden", side === "leading" ? "left-0" : "right-0 flex-row", !dragging && cn("transition-[width]", MOTION)),
51
+ style: {
52
+ width: width
53
+ },
54
+ children: ordered.map(function (action, idx) {
55
+ var _action$key;
56
+ var grow = armed && action === first;
57
+ var collapsed = armed && action !== first;
58
+ return jsxs("button", {
59
+ type: "button",
60
+ tabIndex: open ? 0 : -1,
61
+ disabled: action.disabled || undefined,
62
+ "data-tone": action.tone || "default",
63
+ className: cn("flex min-w-0 flex-col items-center justify-center gap-1 overflow-hidden px-2 text-xs font-medium outline-none", "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-50", "disabled:cursor-not-allowed disabled:opacity-60", toneClass(action.tone), grow ? "flex-[1_0_auto]" : collapsed ? "w-0 flex-none px-0" : "flex-1", !dragging && cn("transition-[flex-grow,width]", MOTION)),
64
+ onClick: function onClick(e) {
65
+ e.stopPropagation();
66
+ onSelect(action, "button");
67
+ },
68
+ children: [action.icon != null && jsx("span", {
69
+ className: "inline-flex shrink-0",
70
+ "aria-hidden": "true",
71
+ children: renderIcon(action.icon, "h-5 w-5")
72
+ }), jsx("span", {
73
+ className: "max-w-full truncate",
74
+ children: action.label
75
+ })]
76
+ }, (_action$key = action.key) !== null && _action$key !== void 0 ? _action$key : "".concat(side, "-").concat(idx));
77
+ })
78
+ });
79
+ }
80
+ var SwipeableListItem = /*#__PURE__*/React.forwardRef(function SwipeableListItem(_ref2, _ref4) {
81
+ var _ref2$as = _ref2.as,
82
+ Component = _ref2$as === void 0 ? "div" : _ref2$as,
83
+ children = _ref2.children,
84
+ _ref2$leadingActions = _ref2.leadingActions,
85
+ leadingActions = _ref2$leadingActions === void 0 ? [] : _ref2$leadingActions,
86
+ _ref2$trailingActions = _ref2.trailingActions,
87
+ trailingActions = _ref2$trailingActions === void 0 ? [] : _ref2$trailingActions,
88
+ _ref2$fullSwipe = _ref2.fullSwipe,
89
+ fullSwipe = _ref2$fullSwipe === void 0 ? true : _ref2$fullSwipe,
90
+ _ref2$fullSwipeThresh = _ref2.fullSwipeThreshold,
91
+ fullSwipeThreshold = _ref2$fullSwipeThresh === void 0 ? 0.6 : _ref2$fullSwipeThresh,
92
+ _ref2$actionWidth = _ref2.actionWidth,
93
+ actionWidth = _ref2$actionWidth === void 0 ? 80 : _ref2$actionWidth,
94
+ open = _ref2.open,
95
+ _ref2$defaultOpen = _ref2.defaultOpen,
96
+ defaultOpen = _ref2$defaultOpen === void 0 ? null : _ref2$defaultOpen,
97
+ onOpenChange = _ref2.onOpenChange,
98
+ _ref2$disabled = _ref2.disabled,
99
+ disabled = _ref2$disabled === void 0 ? false : _ref2$disabled,
100
+ _ref2$moreActions = _ref2.moreActions,
101
+ moreActions = _ref2$moreActions === void 0 ? "focus" : _ref2$moreActions,
102
+ _ref2$moreActionsLabe = _ref2.moreActionsLabel,
103
+ moreActionsLabel = _ref2$moreActionsLabe === void 0 ? "More actions" : _ref2$moreActionsLabe,
104
+ _ref2$menuPresentatio = _ref2.menuPresentation,
105
+ menuPresentation = _ref2$menuPresentatio === void 0 ? "auto" : _ref2$menuPresentatio,
106
+ contentClassName = _ref2.contentClassName,
107
+ className = _ref2.className,
108
+ onKeyDown = _ref2.onKeyDown,
109
+ rest = _objectWithoutProperties(_ref2, _excluded);
110
+ var leading = useMemo(function () {
111
+ return Array.isArray(leadingActions) ? leadingActions : [];
112
+ }, [leadingActions]);
113
+ var trailing = useMemo(function () {
114
+ return Array.isArray(trailingActions) ? trailingActions : [];
115
+ }, [trailingActions]);
116
+ var widths = useMemo(function () {
117
+ return {
118
+ leading: leading.length * actionWidth,
119
+ trailing: trailing.length * actionWidth
120
+ };
121
+ }, [leading.length, trailing.length, actionWidth]);
122
+ var _useControllableState = useControllableState({
123
+ value: open,
124
+ defaultValue: defaultOpen,
125
+ onChange: onOpenChange
126
+ }),
127
+ _useControllableState2 = _slicedToArray(_useControllableState, 2),
128
+ rawOpenSide = _useControllableState2[0],
129
+ setOpenSide = _useControllableState2[1];
130
+ // A side without actions can't be open.
131
+ var openSide = rawOpenSide && widths[rawOpenSide] > 0 ? rawOpenSide : null;
132
+ var rootRef = useRef(null);
133
+ var _useState = useState(null),
134
+ _useState2 = _slicedToArray(_useState, 2),
135
+ moreButtonEl = _useState2[0],
136
+ setMoreButtonEl = _useState2[1];
137
+ var _useState3 = useState(false),
138
+ _useState4 = _slicedToArray(_useState3, 2),
139
+ menuOpen = _useState4[0],
140
+ setMenuOpen = _useState4[1];
141
+ var close = useCallback(function () {
142
+ if (openSide != null) setOpenSide(null);
143
+ }, [openSide, setOpenSide]);
144
+ var runAction = useCallback(function (action, source) {
145
+ var _action$onSelect;
146
+ if (!action || action.disabled) return;
147
+ (_action$onSelect = action.onSelect) === null || _action$onSelect === void 0 || _action$onSelect.call(action, {
148
+ action: action,
149
+ source: source
150
+ });
151
+ setOpenSide(null);
152
+ }, [setOpenSide]);
153
+ var allowFull = _typeof(fullSwipe) === "object" && fullSwipe !== null ? {
154
+ leading: fullSwipe.leading !== false,
155
+ trailing: fullSwipe.trailing !== false
156
+ } : {
157
+ leading: Boolean(fullSwipe),
158
+ trailing: Boolean(fullSwipe)
159
+ };
160
+ var onSettle = function onSettle(_ref3) {
161
+ var side = _ref3.side,
162
+ commit = _ref3.commit;
163
+ if (commit) {
164
+ runAction((side === "leading" ? leading : trailing)[0], "full-swipe");
165
+ return;
166
+ }
167
+ if (side !== openSide) setOpenSide(side);
168
+ };
169
+ var enabled = !disabled && (widths.leading > 0 || widths.trailing > 0);
170
+ var _useSwipeGesture = useSwipeGesture({
171
+ enabled: enabled,
172
+ widths: widths,
173
+ openSide: openSide,
174
+ fullSwipe: allowFull,
175
+ fullSwipeThreshold: fullSwipeThreshold,
176
+ onSettle: onSettle
177
+ }),
178
+ offset = _useSwipeGesture.offset,
179
+ dragging = _useSwipeGesture.dragging,
180
+ armed = _useSwipeGesture.armed,
181
+ handlers = _useSwipeGesture.handlers,
182
+ consumeClick = _useSwipeGesture.consumeClick;
183
+ useClickOutside([rootRef], close, {
184
+ enabled: openSide != null
185
+ });
186
+ var x = offset !== null && offset !== void 0 ? offset : restingOffset(openSide, widths);
187
+ var menuItems = useMemo(function () {
188
+ return [].concat(_toConsumableArray(leading), _toConsumableArray(trailing)).map(function (action, idx) {
189
+ var _action$key2;
190
+ return {
191
+ key: (_action$key2 = action.key) !== null && _action$key2 !== void 0 ? _action$key2 : "action-".concat(idx),
192
+ label: action.label,
193
+ icon: action.icon != null ? renderIcon(action.icon, "h-4 w-4") : null,
194
+ disabled: Boolean(action.disabled),
195
+ tone: isMenuDestructive(action.tone) ? "destructive" : "default",
196
+ onSelect: function onSelect() {
197
+ return runAction(action, "menu");
198
+ }
199
+ };
200
+ });
201
+ }, [leading, trailing, runAction]);
202
+ var hasActions = menuItems.length > 0;
203
+ var showMore = hasActions && moreActions !== false && !disabled;
204
+ var handleKeyDown = function handleKeyDown(e) {
205
+ onKeyDown === null || onKeyDown === void 0 || onKeyDown(e);
206
+ if (e.defaultPrevented) return;
207
+ if (e.key === "Escape" && openSide != null) {
208
+ e.stopPropagation();
209
+ setOpenSide(null);
210
+ }
211
+ };
212
+ return jsxs(Component, _objectSpread2(_objectSpread2({
213
+ ref: function ref(node) {
214
+ return setRefs(node, rootRef, _ref4);
215
+ },
216
+ "data-swipe-open": openSide !== null && openSide !== void 0 ? openSide : undefined,
217
+ "data-swiping": dragging || undefined,
218
+ className: cn("group/swipe relative isolate overflow-hidden", className),
219
+ onKeyDown: handleKeyDown
220
+ }, rest), {}, {
221
+ children: [widths.leading > 0 && jsx(ActionPanel, {
222
+ side: "leading",
223
+ actions: leading,
224
+ width: Math.max(0, x),
225
+ open: openSide === "leading",
226
+ armed: armed === "leading",
227
+ dragging: dragging,
228
+ onSelect: runAction
229
+ }), widths.trailing > 0 && jsx(ActionPanel, {
230
+ side: "trailing",
231
+ actions: trailing,
232
+ width: Math.max(0, -x),
233
+ open: openSide === "trailing",
234
+ armed: armed === "trailing",
235
+ dragging: dragging,
236
+ onSelect: runAction
237
+ }), jsx("div", _objectSpread2(_objectSpread2({
238
+ "data-swipe-content": "",
239
+ className: cn("relative bg-surface touch-pan-y", dragging ? "select-none" : cn("transition-transform", MOTION), contentClassName),
240
+ style: x ? {
241
+ transform: "translate3d(".concat(x, "px, 0, 0)")
242
+ } : undefined
243
+ }, handlers), {}, {
244
+ onClickCapture: function onClickCapture(e) {
245
+ // The click that ends a swipe, or a tap on an open row, only closes.
246
+ var endedSwipe = consumeClick();
247
+ if (!endedSwipe && openSide == null) return;
248
+ e.stopPropagation();
249
+ e.preventDefault();
250
+ if (!endedSwipe) close();
251
+ },
252
+ children: children
253
+ })), showMore && jsx("button", {
254
+ ref: setMoreButtonEl,
255
+ type: "button",
256
+ "aria-label": moreActionsLabel,
257
+ "aria-haspopup": "menu",
258
+ "aria-expanded": menuOpen,
259
+ "data-swipe-more": "",
260
+ className: cn("absolute right-2 top-1/2 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full", "border border-line bg-surface text-foreground shadow-sm outline-none", "focus-visible:ring-2 focus-visible:ring-primary-500 transition-opacity duration-fast motion-reduce:transition-none", moreActions === "focus" && !menuOpen && "pointer-events-none opacity-0 focus-visible:pointer-events-auto focus-visible:opacity-100 [@media(hover:hover)]:group-hover/swipe:pointer-events-auto [@media(hover:hover)]:group-hover/swipe:opacity-100", openSide != null && "hidden"),
261
+ onClick: function onClick(e) {
262
+ e.stopPropagation();
263
+ setMenuOpen(function (v) {
264
+ return !v;
265
+ });
266
+ },
267
+ children: jsx(MoreHorizontal, {
268
+ className: "h-5 w-5",
269
+ "aria-hidden": "true"
270
+ })
271
+ }), showMore && jsx(ActionMenuSurface, {
272
+ open: menuOpen,
273
+ onClose: function onClose() {
274
+ return setMenuOpen(false);
275
+ },
276
+ anchorEl: moreButtonEl,
277
+ items: menuItems,
278
+ presentation: menuPresentation,
279
+ placement: "bottom-end",
280
+ label: moreActionsLabel
281
+ })]
282
+ }));
283
+ });
284
+ SwipeableListItem.displayName = "SwipeableListItem";
285
+
286
+ export { SwipeableListItem as default };