@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,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';
@@ -2,9 +2,11 @@
2
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
4
  import { forwardRef, useId, useRef, useState, useEffect, useCallback } from 'react';
5
- import { Check } from 'lucide-react';
5
+ import { Check, Minus } from 'lucide-react';
6
+ import { cn } from '../../utils/cn.js';
7
+ import { useHaptics } from '../../hooks/useHaptics.js';
6
8
 
7
- var _excluded = ["id", "name", "label", "checked", "defaultChecked", "onChange", "disabled", "required", "className", "size", "labelPosition", "value", "ariaLabel", "variant", "indeterminate", "borderColor", "color", "iconClass", "checkedClass", "wrapperProps"];
9
+ var _excluded = ["id", "name", "label", "checked", "defaultChecked", "onChange", "disabled", "required", "className", "size", "labelPosition", "value", "ariaLabel", "variant", "indeterminate", "color", "iconClass", "checkedClass", "wrapperProps", "haptics"];
8
10
  var SIZE_CLASSES = {
9
11
  sm: {
10
12
  box: "h-4 w-4",
@@ -22,52 +24,56 @@ var SIZE_CLASSES = {
22
24
  icon: "w-4 h-4"
23
25
  }
24
26
  };
27
+ // `checked` paints the box from the native :checked state; `fill` is the same
28
+ // paint applied from React state for the indeterminate (mixed) state.
29
+ // Token presets only: the raw-palette presets (blue / indigo / purple) were
30
+ // removed in 2.0.0 (DTUI-65).
25
31
  var COLOR_PRESETS = {
26
32
  primary: {
27
- checked: "peer-checked:bg-primary-600 peer-checked:border-primary-600 peer-checked:text-white",
28
- ring: "peer-focus:ring-primary-300"
33
+ checked: "peer-checked:bg-primary-600 peer-checked:border-primary-600 peer-checked:text-white dark:peer-checked:bg-primary-500 dark:peer-checked:border-primary-500",
34
+ fill: "bg-primary-600 border-primary-600 text-white dark:bg-primary-500 dark:border-primary-500",
35
+ ring: "peer-focus-visible:ring-primary-500"
29
36
  },
30
37
  secondary: {
31
- checked: "peer-checked:bg-secondary-600 peer-checked:border-secondary-600 peer-checked:text-white",
32
- ring: "peer-focus:ring-secondary-300"
38
+ checked: "peer-checked:bg-secondary-600 peer-checked:border-secondary-600 peer-checked:text-white dark:peer-checked:bg-secondary-500 dark:peer-checked:border-secondary-500",
39
+ fill: "bg-secondary-600 border-secondary-600 text-white dark:bg-secondary-500 dark:border-secondary-500",
40
+ ring: "peer-focus-visible:ring-secondary-500"
33
41
  },
34
42
  success: {
35
- checked: "peer-checked:bg-success-600 peer-checked:border-success-600 peer-checked:text-white",
36
- ring: "peer-focus:ring-success-300"
43
+ checked: "peer-checked:bg-success-600 peer-checked:border-success-600 peer-checked:text-white dark:peer-checked:bg-success-500 dark:peer-checked:border-success-500",
44
+ fill: "bg-success-600 border-success-600 text-white dark:bg-success-500 dark:border-success-500",
45
+ ring: "peer-focus-visible:ring-success-500"
37
46
  },
38
47
  green: {
39
- checked: "peer-checked:bg-success-600 peer-checked:border-success-600 peer-checked:text-white",
40
- ring: "peer-focus:ring-success-300"
48
+ checked: "peer-checked:bg-success-600 peer-checked:border-success-600 peer-checked:text-white dark:peer-checked:bg-success-500 dark:peer-checked:border-success-500",
49
+ fill: "bg-success-600 border-success-600 text-white dark:bg-success-500 dark:border-success-500",
50
+ ring: "peer-focus-visible:ring-success-500"
41
51
  },
42
52
  error: {
43
- checked: "peer-checked:bg-error-600 peer-checked:border-error-600 peer-checked:text-white",
44
- ring: "peer-focus:ring-error-300"
53
+ checked: "peer-checked:bg-error-600 peer-checked:border-error-600 peer-checked:text-white dark:peer-checked:bg-error-500 dark:peer-checked:border-error-500",
54
+ fill: "bg-error-600 border-error-600 text-white dark:bg-error-500 dark:border-error-500",
55
+ ring: "peer-focus-visible:ring-error-500"
45
56
  },
46
57
  danger: {
47
- checked: "peer-checked:bg-error-600 peer-checked:border-error-600 peer-checked:text-white",
48
- ring: "peer-focus:ring-error-300"
58
+ checked: "peer-checked:bg-error-600 peer-checked:border-error-600 peer-checked:text-white dark:peer-checked:bg-error-500 dark:peer-checked:border-error-500",
59
+ fill: "bg-error-600 border-error-600 text-white dark:bg-error-500 dark:border-error-500",
60
+ ring: "peer-focus-visible:ring-error-500"
49
61
  },
50
62
  red: {
51
- checked: "peer-checked:bg-error-600 peer-checked:border-error-600 peer-checked:text-white",
52
- ring: "peer-focus:ring-error-300"
63
+ checked: "peer-checked:bg-error-600 peer-checked:border-error-600 peer-checked:text-white dark:peer-checked:bg-error-500 dark:peer-checked:border-error-500",
64
+ fill: "bg-error-600 border-error-600 text-white dark:bg-error-500 dark:border-error-500",
65
+ ring: "peer-focus-visible:ring-error-500"
53
66
  },
54
67
  warning: {
55
- checked: "peer-checked:bg-warning-600 peer-checked:border-warning-600 peer-checked:text-white",
56
- ring: "peer-focus:ring-warning-300"
57
- },
58
- blue: {
59
- checked: "peer-checked:bg-blue-600 peer-checked:border-blue-600 peer-checked:text-white",
60
- ring: "peer-focus:ring-blue-300"
61
- },
62
- indigo: {
63
- checked: "peer-checked:bg-indigo-600 peer-checked:border-indigo-600 peer-checked:text-white",
64
- ring: "peer-focus:ring-indigo-300"
65
- },
66
- purple: {
67
- checked: "peer-checked:bg-purple-600 peer-checked:border-purple-600 peer-checked:text-white",
68
- ring: "peer-focus:ring-purple-300"
68
+ checked: "peer-checked:bg-warning-600 peer-checked:border-warning-600 peer-checked:text-white dark:peer-checked:bg-warning-500 dark:peer-checked:border-warning-500",
69
+ fill: "bg-warning-600 border-warning-600 text-white dark:bg-warning-500 dark:border-warning-500",
70
+ ring: "peer-focus-visible:ring-warning-500"
69
71
  }
70
72
  };
73
+ // The invisible native input is the hit area: the box size with a mouse,
74
+ // 44×44 centred on the box on coarse pointers.
75
+ var HIT_AREA = "absolute left-1/2 top-1/2 h-full w-full -translate-x-1/2 -translate-y-1/2 [@media(pointer:coarse)]:h-11 [@media(pointer:coarse)]:w-11";
76
+ var ICON_MOTION = "pointer-events-none absolute transition-[opacity,transform] duration-fast ease-standard motion-reduce:transition-none";
71
77
  var Checkbox = /*#__PURE__*/forwardRef(function (_ref, ref) {
72
78
  var id = _ref.id,
73
79
  name = _ref.name,
@@ -90,12 +96,13 @@ var Checkbox = /*#__PURE__*/forwardRef(function (_ref, ref) {
90
96
  _ref.variant;
91
97
  var _ref$indeterminate = _ref.indeterminate,
92
98
  indeterminate = _ref$indeterminate === void 0 ? false : _ref$indeterminate,
93
- borderColor = _ref.borderColor,
94
99
  _ref$color = _ref.color,
95
100
  color = _ref$color === void 0 ? "primary" : _ref$color,
96
101
  iconClass = _ref.iconClass,
97
102
  checkedClass = _ref.checkedClass,
98
103
  wrapperProps = _ref.wrapperProps,
104
+ _ref$haptics = _ref.haptics,
105
+ haptics = _ref$haptics === void 0 ? false : _ref$haptics,
99
106
  props = _objectWithoutProperties(_ref, _excluded);
100
107
  var autoId = useId();
101
108
  var inputId = id || "".concat(autoId, "-checkbox");
@@ -116,45 +123,45 @@ var Checkbox = /*#__PURE__*/forwardRef(function (_ref, ref) {
116
123
  if (!inputRef.current) return;
117
124
  inputRef.current.indeterminate = Boolean(indeterminate);
118
125
  }, [indeterminate]);
126
+ var _useHaptics = useHaptics({
127
+ enabled: haptics
128
+ }),
129
+ haptic = _useHaptics.trigger;
119
130
  var handleChange = useCallback(function (e) {
120
131
  if (!isControlled) setInternalChecked(e.target.checked);
132
+ haptic("selection");
121
133
  if (typeof onChange === "function") onChange(e);
122
- }, [isControlled, onChange]);
134
+ }, [isControlled, onChange, haptic]);
123
135
  var sizeClass = SIZE_CLASSES[size] || SIZE_CLASSES.md;
124
- var wrapperCls = "inline-flex items-center ".concat(className);
125
- var boxOuterCls = "relative inline-flex items-center justify-center rounded-sm border transition-shadow ".concat(sizeClass.box, " ").concat(disabled ? "opacity-60 cursor-not-allowed" : "cursor-pointer hover:shadow-sm", " ");
126
- // Icon classes driven by React state (reliable)
127
- var iconBase = "pointer-events-none transform transition-all duration-150 ease-out";
128
- var iconShown = "opacity-100 scale-100";
129
- var iconHidden = "opacity-0 scale-75";
130
136
  var isPreset = COLOR_PRESETS[color];
131
- var colorClasses = isPreset ? "".concat(isPreset.checked, " peer-focus:ring-2 peer-focus:ring-offset-1 ").concat(isPreset.ring) : "peer-focus:ring-2 peer-focus:ring-offset-1 peer-focus:ring-primary-300";
132
- var customColorStyle = currentChecked && !isPreset && !checkedClass ? {
137
+ var isMixed = Boolean(indeterminate);
138
+ var isPainted = Boolean(currentChecked) || isMixed;
139
+ var customColorStyle = isPainted && !isPreset && !checkedClass ? {
133
140
  backgroundColor: color,
134
141
  borderColor: color,
135
142
  color: "#ffffff"
136
143
  } : {};
137
144
  // The outer box shows its own border unless a checked preset or custom colour paints it.
138
- var showBoxBorder = !(currentChecked && (isPreset || customColorStyle.borderColor));
145
+ var showBoxBorder = !(isPainted && (isPreset || customColorStyle.borderColor));
146
+ var iconState = function iconState(shown) {
147
+ return shown ? "opacity-100 scale-100" : "opacity-0 scale-50";
148
+ };
139
149
  return jsxs("div", _objectSpread2(_objectSpread2({
140
- className: wrapperCls
150
+ className: cn("inline-flex items-center", className)
141
151
  }, wrapperProps !== null && wrapperProps !== void 0 ? wrapperProps : {}), {}, {
142
152
  children: [label && labelPosition === "left" && jsx("label", {
143
153
  htmlFor: inputId,
144
- className: "".concat(sizeClass.label, " select-none mr-2"),
154
+ className: cn(sizeClass.label, "select-none mr-2 text-foreground"),
145
155
  children: label
146
156
  }), jsxs("div", {
147
- className: "".concat(boxOuterCls).concat(!disabled && showBoxBorder && !borderColor ? " border-gray-300" : ""),
148
- style: disabled || !showBoxBorder || !borderColor ? {} : {
149
- borderColor: borderColor
150
- },
157
+ className: cn("relative inline-flex shrink-0 items-center justify-center rounded-sm border transition-shadow duration-fast motion-reduce:transition-none", sizeClass.box, disabled ? "opacity-60 cursor-not-allowed" : "cursor-pointer hover:shadow-sm", !disabled && showBoxBorder && "border-gray-300 dark:border-gray-600"),
151
158
  "aria-disabled": disabled,
152
159
  children: [jsx("input", _objectSpread2({
153
160
  id: inputId,
154
161
  ref: inputRef,
155
162
  name: name,
156
163
  type: "checkbox",
157
- className: "peer absolute inset-0 m-0 p-0 opacity-0 z-10",
164
+ className: cn("peer m-0 p-0 opacity-0 z-10", HIT_AREA, disabled ? "cursor-not-allowed" : "cursor-pointer"),
158
165
  // ensure we set checked only from the boolean (avoid undefined)
159
166
  checked: Boolean(currentChecked),
160
167
  onChange: handleChange,
@@ -162,23 +169,31 @@ var Checkbox = /*#__PURE__*/forwardRef(function (_ref, ref) {
162
169
  required: required,
163
170
  value: value,
164
171
  "aria-label": ariaLabel,
165
- "aria-checked": Boolean(currentChecked)
166
- }, props)), jsx("div", {
167
- className: "pointer-events-none z-0 flex items-center justify-center rounded-sm w-full h-full transition-colors duration-150 ease-in-out " + "".concat(colorClasses, " ") + "".concat(disabled ? "bg-gray-100 border-gray-400 text-primary-400" : "bg-white border-gray-500", " ").concat(checkedClass ? checkedClass : ""),
168
- style: currentChecked && checkedClass ? {
172
+ "aria-checked": isMixed ? "mixed" : Boolean(currentChecked)
173
+ }, props)), jsxs("div", {
174
+ className: cn("pointer-events-none relative z-0 flex items-center justify-center rounded-sm w-full h-full", "transition-colors duration-fast ease-standard motion-reduce:transition-none",
175
+ // Keyboard focus ring drawn on the visual box (the input is invisible).
176
+ "peer-focus-visible:ring-2 peer-focus-visible:ring-offset-1 dark:peer-focus-visible:ring-offset-gray-900", isPreset ? isPreset.ring : "peer-focus-visible:ring-primary-500", disabled ? "bg-gray-100 text-primary-400 dark:bg-gray-800" : "bg-surface", isPreset && isPreset.checked, isPreset && isMixed && !checkedClass && isPreset.fill, checkedClass),
177
+ style: isPainted && checkedClass ? {
169
178
  backgroundColor: "",
170
179
  borderColor: ""
171
180
  } : customColorStyle,
172
181
  "aria-hidden": "true",
173
- children: jsx(Check, {
174
- className: "".concat(sizeClass.icon, " ").concat(iconBase, " ").concat(currentChecked ? iconShown : iconHidden, " ").concat(iconClass || ""),
182
+ children: [jsx(Check, {
183
+ className: cn(sizeClass.icon, ICON_MOTION, iconState(currentChecked && !isMixed), iconClass),
175
184
  strokeWidth: 2.2,
176
- "aria-hidden": "true"
177
- })
185
+ "aria-hidden": "true",
186
+ "data-icon": "check"
187
+ }), jsx(Minus, {
188
+ className: cn(sizeClass.icon, ICON_MOTION, iconState(isMixed), iconClass),
189
+ strokeWidth: 2.6,
190
+ "aria-hidden": "true",
191
+ "data-icon": "indeterminate"
192
+ })]
178
193
  })]
179
194
  }), label && labelPosition === "right" && jsx("label", {
180
195
  htmlFor: inputId,
181
- className: "".concat(sizeClass.label, " select-none ml-2"),
196
+ className: cn(sizeClass.label, "select-none ml-2 text-foreground"),
182
197
  children: label
183
198
  })]
184
199
  }));
@@ -3,6 +3,7 @@ import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
  import { forwardRef, useId, useMemo, useState } from 'react';
5
5
  import { cn } from '../../utils/cn.js';
6
+ import Slider from './Slider.js';
6
7
 
7
8
  var _excluded = ["value", "defaultValue", "onChange", "swatches", "showAlpha", "size", "disabled", "className", "label", "id"];
8
9
  /**
@@ -121,6 +122,14 @@ function parseColor(input) {
121
122
  }
122
123
  return null;
123
124
  }
125
+ // Same colour (alpha compared to 3 decimals, like the output string).
126
+ function sameColor(x, y) {
127
+ var _x$a, _y$a;
128
+ if (!x || !y) return false;
129
+ var ax = +((_x$a = x.a) !== null && _x$a !== void 0 ? _x$a : 1).toFixed(3);
130
+ var ay = +((_y$a = y.a) !== null && _y$a !== void 0 ? _y$a : 1).toFixed(3);
131
+ return x.r === y.r && x.g === y.g && x.b === y.b && ax === ay;
132
+ }
124
133
  function rgbaToString(_ref2) {
125
134
  var r = _ref2.r,
126
135
  g = _ref2.g,
@@ -132,7 +141,7 @@ function rgbaToString(_ref2) {
132
141
  }
133
142
  // ---------- Component ----------
134
143
  var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
135
- var _internal$a, _internal$a2;
144
+ var _internal$a;
136
145
  var value = props.value,
137
146
  defaultValue = props.defaultValue,
138
147
  onChange = props.onChange,
@@ -224,8 +233,10 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
224
233
  children: label
225
234
  }), jsxs("div", {
226
235
  className: "flex ".concat(sizeMap.gap, " items-start flex-col"),
227
- children: [jsx("div", {
236
+ children: [swatches.length > 0 && jsx("div", {
228
237
  className: "flex flex-wrap ".concat(sizeMap.gap),
238
+ role: "group",
239
+ "aria-label": "Swatches",
229
240
  children: swatches.map(function (s, i) {
230
241
  var _parseColor;
231
242
  var c = (_parseColor = parseColor(s)) !== null && _parseColor !== void 0 ? _parseColor : {
@@ -234,38 +245,41 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
234
245
  b: 0,
235
246
  a: 1
236
247
  };
248
+ var selected = sameColor(c, internal);
237
249
  return jsx("button", {
238
250
  type: "button",
239
251
  "aria-label": "Select ".concat(s),
252
+ "aria-pressed": selected,
240
253
  disabled: disabled,
241
254
  onClick: function onClick() {
242
255
  return pushChange(c);
243
256
  },
244
- className: "rounded-md border border-gray-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-primary-500 ".concat(sizeMap.swatch, " overflow-hidden"),
257
+ className: cn("rounded-md border border-line overflow-hidden transition-shadow duration-fast motion-reduce:transition-none", "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-primary-500 dark:focus-visible:ring-offset-gray-900", "disabled:cursor-not-allowed disabled:opacity-50", selected && "ring-2 ring-offset-2 ring-primary-500 dark:ring-offset-gray-900", sizeMap.swatch),
245
258
  style: {
246
259
  background: "rgba(".concat(c.r, ",").concat(c.g, ",").concat(c.b, ",").concat(c.a, ")")
247
260
  },
248
- title: s
261
+ title: s,
262
+ "data-selected": selected || undefined
249
263
  }, i);
250
264
  })
251
265
  }), jsxs("div", {
252
- className: "flex-1 min-w-[220px]",
266
+ className: "w-full sm:flex-1 sm:min-w-[220px]",
253
267
  children: [jsxs("div", {
254
- className: "flex items-center gap-3",
268
+ className: "flex flex-wrap items-center gap-3",
255
269
  children: [jsxs("div", {
256
270
  className: "flex items-center gap-2",
257
271
  children: [jsx("div", {
258
- className: "rounded-md border border-gray-200 overflow-hidden w-12 h-12 flex items-center justify-center",
272
+ className: "rounded-md border border-line overflow-hidden w-12 h-12 flex items-center justify-center",
259
273
  style: {
260
274
  background: "rgba(".concat(internal.r, ", ").concat(internal.g, ", ").concat(internal.b, ", ").concat(internal.a, ")")
261
275
  }
262
276
  }), jsxs("div", {
263
277
  className: "flex flex-col",
264
278
  children: [jsx("div", {
265
- className: "text-xs text-primary-500",
279
+ className: "text-xs text-primary-500 dark:text-primary-300",
266
280
  children: "Current"
267
281
  }), jsx("div", {
268
- className: "font-mono text-sm",
282
+ className: "font-mono text-sm text-foreground",
269
283
  children: rgbaToHex(internal, showAlpha)
270
284
  })]
271
285
  })]
@@ -282,7 +296,7 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
282
296
  className: "w-10 h-10 p-0 border-none bg-transparent",
283
297
  "aria-label": "Native color input"
284
298
  }), jsxs("div", {
285
- className: "flex-1",
299
+ className: "min-w-[8rem] flex-1",
286
300
  children: [jsx("span", {
287
301
  id: valueLabelId,
288
302
  className: "sr-only",
@@ -303,17 +317,21 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
303
317
  }));
304
318
  }
305
319
  },
306
- className: "w-full rounded-md border border-gray-200 px-2 py-1 font-mono",
320
+ className: "w-full rounded-md border border-line bg-surface px-2 py-1 font-mono text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 disabled:opacity-50",
307
321
  "aria-labelledby": "".concat(labelId, " ").concat(valueLabelId)
308
322
  })]
309
323
  })]
310
324
  }), jsx("div", {
311
325
  className: "mt-3 space-y-2",
312
326
  children: showAlpha && jsx(Slider, {
313
- label: "Alpha (".concat(Math.round(((_internal$a = internal.a) !== null && _internal$a !== void 0 ? _internal$a : 1) * 100), "%)"),
327
+ label: "Alpha",
328
+ showValue: true,
329
+ formatValue: function formatValue(v) {
330
+ return "".concat(v, "%");
331
+ },
314
332
  min: 0,
315
333
  max: 100,
316
- value: Math.round(((_internal$a2 = internal.a) !== null && _internal$a2 !== void 0 ? _internal$a2 : 1) * 100),
334
+ value: Math.round(((_internal$a = internal.a) !== null && _internal$a !== void 0 ? _internal$a : 1) * 100),
317
335
  onChange: function onChange(v) {
318
336
  pushChange(_objectSpread2(_objectSpread2({}, internal), {}, {
319
337
  a: clamp(v / 100, 0, 1)
@@ -327,34 +345,5 @@ var ColorPicker = /*#__PURE__*/forwardRef(function ColorPicker(props, ref) {
327
345
  }));
328
346
  });
329
347
  ColorPicker.displayName = "ColorPicker";
330
- function Slider(_ref4) {
331
- var label = _ref4.label,
332
- min = _ref4.min,
333
- max = _ref4.max,
334
- value = _ref4.value,
335
- _onChange = _ref4.onChange,
336
- disabled = _ref4.disabled;
337
- return jsxs("div", {
338
- className: "flex items-center gap-3",
339
- children: [jsx("div", {
340
- className: "w-36 text-sm text-primary-600",
341
- children: label
342
- }), jsx("input", {
343
- type: "range",
344
- min: min,
345
- max: max,
346
- value: value,
347
- disabled: disabled,
348
- onChange: function onChange(e) {
349
- return _onChange(Number(e.target.value));
350
- },
351
- className: "w-full h-2 rounded-lg appearance-none bg-gray-200",
352
- "aria-label": label
353
- }), jsx("div", {
354
- className: "w-14 text-right font-mono text-sm",
355
- children: value
356
- })]
357
- });
358
- }
359
348
 
360
349
  export { ColorPicker as default };